【附加题】《Java170道面试笔试题全面含答案》涉及java/数据库/框架/系统/设计模式相关

时间:2022-10-21 09:09:52
1. Java的泛型是如何工作的 ? 什么是类型擦除 ?


这是一道更好的泛型面试题。泛型是通过类型擦除来实现的,编译器在编译时擦除了所有类型相关的信息,所以在运行时不存在任何类型相关的信息。例如 List<String>在运行时仅用一个List来表示。这样做的目的,是确保能和Java 5之前的版本开发二进制类库进行兼容。你无法在运行时访问到类型参数,因为编译器已经把泛型类型转换成了原始类型。根据你对这个泛型问题的回答情况,你会 得到一些后续提问,比如为什么泛型是由类型擦除来实现的或者给你展示一些会导致编译器出错的错误泛型代码。请阅读我的Java中泛型是如何工作的来了解更 多信息。




2、hashtable,concurrenthashmap为什么键和值不能为null,而hashmap可以?





因为hashtable,concurrenthashmap它们是用于多线程的,并发的 ,如果map.get(key)得到了null,不能判断到底是映射的value是null,还是因为没有找到对应的key而为空,而用于单线程状态的hashmap却可以用containskey() 去判断到底是否包含了这个null。


3、Spring声明式事务的五种方式?





《看我博客》
事务自动代理BeanNameAutoProxyCreator相结合的方式事务拦截器TransactionInterceptor


4、hashmap为什么线程不安全?

void resize(int i)  
    {  
        Entry aentry[] = table;  
        
        {  
            Entry aentry1[] = new Entry[i];  
            transfer(aentry1, initHashSeedAsNeeded(i));  
            table = aentry1;  
            threshold = (int)Math.min((float)i * loadFactor, 1.073742E+009F);  
            return;  
        }  
    }  


当多个线程同时检测到总数量超过门限值的时候就会同时调用resize操作,各自生成新的数组并rehash后赋给该map底层的数组table,结果最终只有最后一个线程生成的新数组被赋给table变量,其他线程的均会丢失。而且当某些线程已经完成赋值而其他线程刚开始的时候,就会用已经被赋值的table作为原始数组,这样也会有问题。


5、加载因子
其中loadFactor加载因子是表示Hsah表中元素的填满的程度.


若:加载因子越大,填满的元素越多,好处是,空间利用率高了,但:冲突的机会加大了.链表长度会越来越长,查找效率降低。


反之,加载因子越小,填满的元素越少,好处是:冲突的机会减小了,但:空间浪费多了.表中的数据将过于稀疏(很多空间还没用,就开始扩容了)


冲突的机会越大,则查找的成本越高.


因此,必须在 "冲突的机会"与"空间利用率"之间寻找一种平衡与折衷. 这种平衡与折衷本质上是数据结构中有名的"时-空"矛盾的平衡与折衷.


如果机器内存足够,并且想要提高查询速度的话可以将加载因子设置小一点;相反如果机器内存紧张,并且对查询速度没有什么要求的话可以将加载因子设置大一点。不过一般我们都不用去设置它,让它取默认值0.75就好了。


6、运行结果题












补充
class HelloA {
	public HelloA() {
		System.out.println("HelloA");
	}


	{
		System.out.println("I'm A class");
	}


	static {
		System.out.println("static A");
	}
}


public class HelloB extends HelloA {
	public HelloB() {
		System.out.println("HelloB");
	}


	{
		System.out.println("I'm B class");
	}


	static {
		System.out.println("static B");
	}


	public static void main(String[] args) {
		new HelloB();
	}
}


这个程序的输出结果是:
static A
static B
I'm A class
HelloA
I'm B class
HelloB


补充
public class Test
{
    public static Test t1 = new Test();
	 public Test(){
        System.out.println("Constructor");
    }
    {
         System.out.println("blockA");
    }
    static
    {
        System.out.println("blockB");
    }
    public static void main(String[] args)
    {
        Test t2 = new Test();
    }
 }


 运行结果:
blockA
Constructor
blockB
blockA
Constructor


7、
JAVA子类不可以继承父类的构造方法


子类不可以继承父类的构造方法,只可以调用父类的构造方法。子类中所有的构造函数都会默认访问父类中的空参数构造函数,这是因为子类的构造函数内第一行都有默认的super()语句。super()表示子类在初始化时调用父类的空参数的构造函数来完成初始化。一个类都会有默认的空参数的构造函数,若指定了带参构造函数,那么默认的空参数的构造函数,就不存在了。这时如果子类的构造函数有默认的super()语句,那么就会出现错误,因为父类中没有空参数的构造函数。因此,在子类中默认super()语句,在父类中无对应的构造函数,必须在子类的构造函数中通过this或super(参数)指定要访问的父类中的构造函数


8、线程可重用的理解?


线程重用的核心是,它把Thread.start()给屏蔽起来了(一定不要重复调用),然后它自己有一个Runnable.run(),循环在跑,跑的过程中不断检查我们是否有新加入的子Runnable对象,有就调一下我们的run(),其实就一个大run()把其它小run()#1,run()#2,...给串联起来了,基本原理就这么简单。 


9、数据库查询执行效率


Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看 SQL 语句的执行效 果,可以帮助选择更好的索引和优化查询语句,写出更好的优化语句。
Explain语法:explain select … from … [where ...]
例如:explain select * from news;


10、运行结果
class h extends Thread{
	
	public static void a(){
		System.out.println("a");
	}
	public void run(){
		System.out.println("aa");
	}
}
public class test {


	public static void main(String[] args) {
		// TODO Auto-generated method stub
		h a=new h();
		h b=new h();
		a.start();
		System.out.println("b1");
		b.start();
		System.out.println("b2");
	}


}


运行结果
b1
aa
b2

aa


11、线程池参数 

ThreadPoolExecutor mExecutor = new ThreadPoolExecutor(corePoolSize,// 核心线程数  
                        maximumPoolSize, // 最大线程数  
                        keepAliveTime, // 闲置线程存活时间  
                        TimeUnit.MILLISECONDS,// 时间单位  
                        new LinkedBlockingDeque<Runnable>(),// 线程队列  
                        Executors.defaultThreadFactory(),// 线程工厂  
                        new AbortPolicy()// 队列已满,而且当前线程数已经超过最大线程数时的异常处理策略  
                );

比如去火车站买票, 有10个售票窗口, 但只有5个窗口对外开放. 那么对外开放的5个窗口称为核心线程数, 而最大线程数是10个窗口.如果5个窗口都被占用, 那么后来的人就必须在后面排队, 但后来售票厅人越来越多, 已经人满为患, 就类似于线程队列已满.这时候火车站站长下令, 把剩下的5个窗口也打开, 也就是目前已经有10个窗口同时运行. 后来又来了一批人,10个窗口也处理不过来了, 而且售票厅人已经满了, 这时候站长就下令*入口,不允许其他人再进来, 这就是线程异常处理策略.而线程存活时间指的是, 允许售票员休息的最长时间, 以此限制售票员偷懒的行为.