java笔试面试第一天

时间:2023-03-09 19:52:33
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("执行普通方法里的代码块");
}
} }

  以下是控制台打印结果:

java笔试面试第一天

总结:

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");
}

  控制台打印:

java笔试面试第一天

笔试题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;
} }

  控制台输出结果:

java笔试面试第一天

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

笔试题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;
}
}

  控制台输出:

java笔试面试第一天

总结: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“是在常量池一次定义的对象。。。欢迎各路大神前来指导。