Java小问题集合1

问题1:

代码如下:

public class Test  
{  
    Test t = new Test();  
  
    public static void main(String[] args)  
    {  
        Test t = new Test();  
    }  
}  

程序为何会报错误:Exception in thread "main" java.lang.StackOverflowError;


原因:

1.JAVA中初始化的顺序:加载类、静态成员变量初始化、静态代码块、非静态成员变量初始化、构造方法;后两个是对象的初始化时初始化的;

2.在main方法里new Test(),new了一个Test对象,想要完成Test对象的初始化,就得初始化它的非静态成员变量,于是又new了一个Test对象,想要完成第二个Test对象的初始化,你就得初始化它的非静态成员变量,如此一直递归下去,一直new Test对象,栈的内存就满了;

3.可以添加一点代码,如下,看程序的执行过程;

public class Test
{
	public Test()
	{
		System.out.println("我在实例化");
	}
	Test t = new Test();

	public static void main(String[] args)
	{
		System.out.println("begin");
		Test t = new Test();
	}
}


问题2:

请在程序中指定位置添加一段代码;

public class RightDemo
{
	public static void main(String[] args)
	{
		int i = 0;
		{
			// 添加一段代码使得控制台输出right
		}
		if (i + 1 < i)
		{
			System.out.println("right");
		} 
		else
		{
			System.out.println("wrong");
		}
	}
}


答案:i = Integer.MAX_VALUE;

原因:此题考察的是  Integer.MAX_VALUE+1==Integer.MIN_VALUE;即int类型的最大值加1等于int类型的最小值;


问题3:

为什么要使用数据库连接池?


原因:

(1)JAVA语言通过JDBC技术访问数据库,但使用JDBC会有一些问题,首先,每一次web请求都要建立一次数据库连接,建立连接是一个费时的活动,每次都得花费0.05s~1s的时间,而且系统还要分配内存资源这个时间对于一次或几次数据库操作,或许感觉不出系统有多大的开销。可是对于现在的Web应用,尤其是大型电子商务网站,同时有几百人甚至几千人在线是很正常的事在这种情况下,频繁的进行数据库连接操作势必占用很多的系统资源,网站的响应速度必定下降,严重的甚至会造成服务器的崩溃。

(2)不是危言耸听,这就是制约某些电子商务网站发展的技术瓶颈问题。其次,对于每一次数据库连接,使用完后都得断开。否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将不得不重启数据库。还有,这种开发不能控制被创建的连接对象数,系统资源会被毫无顾及的分配出去,如连接过多,也可能导致内存泄漏,服务器崩溃。

(3)因此,引用了数据库连接池技术数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况,为系统开发﹑测试及性能调整提供依据

(4)通俗的介绍JDBC和连接池就是:连接池里就是JDBC的Connection实例,只不过加了超时等管理,节省资源而已

(5)连接池和JDBC的比喻:想吃苹果,两种方式:1,一次买5个放冰箱里,每次吃的时候从冰箱里拿一个吃;2,想吃的时候买一个;

(6)优点:最主要的就是连接的重复使用,提高性能:



问题4:

一段可读性很差的for循环:

class Fu
{
	boolean show(char a)
	{
		System.out.println(a);
		return true;
	}
}

public class Demo extends Fu
{
	public static void main(String[] args)
	{
		int i = 0;
		Fu f = new Demo();
		Demo d = new Demo();
		for (f.show('A'); f.show('B') && (i < 2); f.show('C'))
		{
			i++;
			d.show('D');
		}
	}

	boolean show(char a)
	{
		System.out.println(a);
		return false;
	}
}

解释一下:

我们常规的for循环中表达式一般不是boolean型,所以感觉可读性很差;

从main方法开始,直接看循环,第一步,f.show('A'),调用Demo类的show方法,打印A;第二步,f.show('B')调用Demo类的show方法,打印B,并且返回值为false,所有这个表达式f.show('B') && (i<2)返回false,条件不成立,终止循环;这个题考察的就是for的执行过程和多态的应用;



问题5:

一段Java的源代码:

public class HashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable

这是java 源代码中关于HashMap的定义,我想知道的是,为什么HashMap的父类AbstractMap已经implements了Map<K,V>接口,而在HashMap的定义中又再一次的声明implements Map<K,V>接口呢,这么做有什么意义呢?


原因:

从编译和运行的角度来说,没有意义。 
但是从读者的角度来说,有意义。 

你可以考虑一下如下场景: 
1,你定义了一个接口,里面有10个抽象方法(接口里面的都是抽象方法) 
2,你有9个抽象类,抽象类1继承接口,实现了1个方法(可以只实现接口的部分方法) 
3,抽象类2继承抽象类1,同时又多实现了一个方法 
4,依次类推,每个抽象类依次继承上面的抽象类,每个都多实现一个方法。 
5,最后你的实现类实现抽象类9,把最后一个未实现的方法实现了。 
那么问题来了 
这时候你读源代码或者文档的时候,你根本不知道你这个类实现了什么接口,如果想知道的话,就要依次把抽象类9,8。。。一直找到抽象类1的时候,你才知道你的这个实现类实际上是实现了你第一步定义的接口,这样是不是对读者很不友好? 

如果每一层都明确声明实现了第一步的接口,那么你看实现类或者任一层次的抽象类的时候,你都不需要再找别的继承关系的类了,因为你可以直接跳到接口去看定义就可以了。 

这就是对读者友好的体现,代码主要是给人看的,对于机器来说,他只需要2进制字节就可以了;

还可以看一下这两篇文章,但都是英文的:

Why does Atomiclnteger implements Serializable

why does LinkedHashSet extends HashSet and implements Set

其中一篇文章的答案是Java的Collections Framework的作者的观点,这个够官方了;



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章