java笔试面试第一天

  好久未曾启用我的博客,最近来上海找工作,想将笔试面试的过程做个记录,毕竟有总结才有提高嘛。今天算是笔试面试正式开始第一天吧,以下就是我的笔试总结(没有原题了,只有知识点):

笔试题1:java static对象的使用:包括静态方法,静态变量,静态代码块,main方法,构造器,普通成员方法等的执行顺序,以代码的形式展现吧。

public class TestMain {

	static {
		System.out.println("执行静态代码块");
	}
	
	public TestMain(){
		System.out.println("执行构造方法");
	}
	
	public static void main(String[] args) {
		System.out.println("执行main方法");
		System.out.println("第一次创建类的实例对象");
		System.out.println("------------------");
		new TestMain();
		System.out.println("第二次创建实例对象");
		System.out.println("------------------");
		new TestMain();
		System.out.println("第三次创建实例对象");
		System.out.println("------------------");
		new TestMain().printHello();

	}
	
	static {
		System.out.println("执行静态代码块2");
	}
	
	{
		System.out.println("代码块1");
	}
	
	{
		System.out.println("代码块2");
	}
	
	public void printHello(){
		System.out.println("执行普通方法");
		
		{
			System.out.println("执行普通方法里的代码块");
		}
	}

}

  以下是控制台打印结果:

总结:

1.类的静态代码块执行顺序先于main方法(不论声明位于main前还是main后),并且在类加载完成期间只执行一次。

2.类的普通代码块(相当于类的实例属性)在new实例的时候执行,并且顺序先于构造器,与普通成员方法一样,只有实例存在才能执行,与普通成员方法不一样的是,不显示调用就被执行。

3.被static修饰的方法叫静态方法,也叫类方法,是类被加载后就被存放于内存里的,并且只存一次(公共方法,静态变量同理),静态方法只能调用静态成员(方法与变量),不能调用非静态成员,是因为非静态成员在没有实例化之前是不存在的!所以同理,静态方法里不能出现this或者super;静态方法可以用:类名.方法名的方式调用,也可以用:对象.方法名的方式调用(不推荐)。

笔试题2:java 中 if ()语句,括号里需要的是boolean类型,if (0)是错误的,if语句后面没有花括号时,紧跟的第一句是判断之后是否执行的语句,与花括号内的语句作用相同。

@Test
	public void testFor(){
		if (false)
			System.out.println("true");
		System.out.println("false");
	}

  控制台打印:

笔试题3:一般for循环:for (int i = 0; true; i++),这种方式不会报错,会无限执行。for循环里的变量“i”作用域仅限后面的花括号(或者紧跟的第一条语句)。

笔试题4:变量的作用域问题:Java用一对大括号作为语句块的范围,称为作用域。下面是有成员变量的情况下变量作用域的代码分析:

public class TestScope {
	private String name = "name1";
	private static String num = "1";

	public static void main(String[] args) {
		
		{
			String name = "name2";
			System.out.println(name); // name2
		} // 作用域失效,所以下面的变量为“name”不会报错。
		
		String name = "name3";
		System.out.println(name); // name3
		
		System.out.println(new TestScope().name); // name1
		
		TestScope ts_1 = new TestScope();
		ts_1.setName("name_mod");
		System.out.println(ts_1.getName()); // name_mod
		
		System.out.println(new TestScope().name); // name1
		System.out.println(new TestScope().getName()); // name1
		
		// 静态成员变量--相当于共有变量,类加载后只存一次,即位置固定
		TestScope ts_2 = new TestScope();
		System.out.println(ts_2.getNum()); // 不推荐用对象调用静态成员  1
		ts_2.setNum("2");
		System.out.println(ts_2.getNum()); // 2
		System.out.println(new TestScope().getNum()); //2
	}
	
	public void setName(String name){
		this.name = name;	
	}
	
	public String getName(){
		return this.name;
	}

	public static String getNum() {
		return num;
	}

	public static void setNum(String num) {
		TestScope.num = num;
	}
	
}

  控制台输出结果:

总结:以上代码也可以说明静态变量与普通成员变量的区别。普通成员变量的初始化值不能通过实例化对象的方法修改,因为每次生成一个新的对象,句柄指向的都是复制过来的新的成员变量,而不是指向真正的成员变量。通过反射进行修改。

笔试题5:java 重写问题:重写(Overriding)是子类与父类之间的多态性的体现,子类重写父类方法,要求:方法名、返回类型、参数表相同,访问权限大于等于父类。

注意:java重载(Overloading)是一个类多态性的体现,即同一个方法根据传参不同实现不同功能。要求:方法名相同,参数表(类型或者个数)不同(只能根据这两个条件判断是否重载,返回值与访问权限不能作为区分标准)。

笔试题6:java  equals()方法与"=="的区别:"=="如果比较两个基本数据类型的时候,是比较数据值,但对于对象来说,"=="比较的就是对象(地址),equals()方法只能被对象调用来进行比较操作,它也是比较对象(地址),只是某些包装类里的equals()方法被重写了,所以看起来像是可以比较对象的值,比如String类就重写了这个方法,所以可以进行以下比较:

public static void main(String[] args) {

		String s1 = "a";
		String s2 = "a";
		String s3 = new String("a");
		
		System.out.println(s1 == s2); // true
		System.out.println(s1 == s3); // false
		System.out.println(s1.equals(s3)); // true
	}

  除了String重写了equals()方法外,大部分能用到的类库里的类都重写了,像Integer,Boolean,Float等包装类,还有Vector,Pair,List,HashMap,Collection,Enum,Set等等,如果自定义类需要用到equals()方法,是需要手动重写的,因为自定义类都继承了Object的类,而Object的equals()方法是没有重写过的,即:只能比较对象的地址,不能比较对象的值(可以看一下API里equals方法的代码)。

这里我也自己写了自定义类重写equals()方法的代码:如果两个对象都是TestString的对象,而且name与num的值都相等,则两个对象相等。

public class TestString {
	
	private String name;
	private int num;
	
	/**
	 * 重写equals方法:如果是TestString的对象而且name与num的值都相等则两个对象相等
	 */
	public boolean equals(Object obj){
		// 如果是对象自己与自己比较
		if (this == obj){
			return true;
		}
		// 如果对象为空,直接返回false
		if (obj == null){
			return false;
		}
		// 如果不是该自定义类的对象,直接返回false
		if (!(obj instanceof TestString)){
			return false;
		}
		TestString ts = (TestString) obj;
		return this.num == ts.num && this.name == ts.name  ;
	}
	
	public static void main(String[] args) {

		TestString ts1 = new TestString();
		ts1.setName("a");
		ts1.setNum(1);
		
		TestString ts2 = new TestString();
		ts2.setName("a");
		ts2.setNum(1);
		System.out.println(ts1 == ts2); // false
		System.out.println(ts1.equals(ts2)); // true
		System.out.println(ts1.equals(new String("a"))); // false
	}
	
	public void setName(String name){
		this.name = name;
	}
	public String getName(){
		return this.name;
	}
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
}

  控制台输出:

总结:Object类里边有这几个方法:equals()、hashCode()、

 笔试题7:String类创建对象的问题,这个问题说实话很让我头疼,从上学那会就对这个“String创建了几个对象”的问题搞的晕头转向,既然笔试到了,那么是时候来个了断了T_T

@Test
	public void testAdd(){
			String str1 = "a";
			String str2 = "a";
			String str3 = "b";
			String str4 = "ab";           
			String str = new String("b");
	        final String str5 = "a";  
			final String str6;

			{
				str6 = "a";
			}
			
			String s1 = "a" + "b"; // 运行时没有生成新的对象,编译过的代码里已经存在 "ab",即str4
			String s2 = str2 + str3; // 运行时生成了新的对象,s2编译过之后不能确定值
			String s3 = str5 + "b"; // 运行时没有生成新对象,str5是常量,所以编译之后是"ab",即str4
			String s4 = str6 + "b"; // 运行时生成了新对象,str6是变量,虽然在代码块里赋了值,但是这条语句编译时还是按变量来算的,只有运行后代码块才被执行
			
			System.out.println(str1 == str2); // true
			System.out.println(s1 == str4); // true
			System.out.println(s2 == str4); // false
			System.out.println(s3 == str4); // true
			System.out.println(s4 == str4); // false
			System.out.println(str3 == str.intern()); // true intern()方法:手动向常量池中添加常量,如果常量池已存在,直接返回地址
			System.out.println(str1 == str6); //ture 说明只要是在代码里出现的,编译时都会被存进常量池里(已知字面量)。
		}

  

  总结:在代码中存在的变量的”赋值“叫“已知字面量”,这些已知字面量在编译后会被存到jvm的常量池中(常量池的问题有待深究),栈里存句柄(引用),堆里存数据,常量池里存常量数据,引用在指向数据的时候会先在常量池中查找,如果有,指向常量池的地址,如果没有从堆里找,这样来思考的话,在用"=="进行比较的时候就知道比较的地址是不是一样了。由于常量池里的数据如果存在就不会再复制,所以可以被多个引用指向,而指向同一个地址的引用 "==" 就是true。(仅仅是本人见解,有错误的地方欢迎指出)。

PS:以上说了半天好像是没有解决到底创建了几个对象的问题【捂脸】,例如:String a = new String("a"); 为什么是创建了两个对象呢?  我理解应该是这样的:字面量"a",在编译后于常量池创建了对象"a",然后程序运行后,在堆中又new了一个实例对象,所以是两个对象。

String a  = "a" + "b" + "c" + "d"; 创建了一个对象,网上说法众多,但是我觉得其中一种说的有道理,就是因为它是一行定义的对象,编译时只会初始化一次常量池的数据,所以”abcd“是在常量池一次定义的对象。。。欢迎各路大神前来指导。

原文地址:https://www.cnblogs.com/chenboaixuexi/p/7645311.html