- 虚函数、抽象函数、接口、抽象类:
虚函数(Virtual)已经包含了也必须包含默认的实现,所以在派生类中可以重新实现也可以不实现这些虚函数。 抽象函数(abstract)没有提供默认实现,所以在派生类中必须实现这些抽象函数。 接口中的函数类似于抽象函数,也不提供默认实现,实现接口的类也必须实现这些函数。 但接口可用于多继承,即,类只能从一个类继承,但可同时实现多个接口。
Java虚函数:虚函数是为了多态的存在,默认写的函数就是虚函数,非虚函数可以加速final修饰词
Java抽象函数:也叫纯虚函数,是为了定义接口,abstract void print();
Java抽象类:抽象类的存在是因为父类中既包括子类共性函数的具体定义,也包括需要子类各自实现的函数接口。抽象类中可以有数据成员和非抽象方法。用abstract修饰的类
Java接口:接口中不能有普通成员变量,函数都是纯虚函数。用interface修饰的类。 - 子类继承父类相关问题:
- case1
public class Base {
String str = "base string";
void init(){
System.out.println("base init");
}
void show(){
System.out.println(str);
init();
}
}
public class Child extends Base {
String str = "child string";
public static void main(String[] args){
Child b = new Child();
b.show();
}
}
结果输出:
base string
base init
有2个类,在Child里面new了一个Child对象,b.show首先会在Child里面寻找是否有show的重写,发现没有,就寻找的Base里面的show方法,base里面的show首先会打印str,也就是this.str,此时是在Base里面寻找是否有该变量(如果有就直接打印,没有的话再去寻找Base的父类);对于show的第二个方法init,首先会看在Child里面是否有对init进行重新(如果重写了就执行Child类里面的init,没有的话就执行Base里面的init)
- case2
public class Base {
String str = "base string";
void init(){
System.out.println("base init");
}
void show(){
System.out.println(str);
init();
}
}
public class Child extends Base {
String str = "child string";
void show(){
System.out.println(str);
}
public static void main(String[] args){
Child b = new Child();
System.out.println(b.str);
b.show();
Base b1 = new Base();
System.out.println(b1.str);
b1.show();
Base b2 = new Child();
System.out.println(b2.str);
b2.show();
}
}
结果输出
child string
child string
base string
base string
base init
base string
child string
为了简化说明,把声明部分称为“part1”(Child d、Base b1、Base b2),把实例化部分称为“part2”(new Child()、new Base()、new Child())
通用:对于成员变量的访问(前提是可以访问到),首先看part1的类型,如果有就返回,没有的话寻找part1的父类;对于类方法的调用,会首先看part2的类型里面有没有该方法的重写(如果有就调用,没有的话就往上找父类)
- case3
“==”:判断的是地址是否相同
基本类如上:
public class Test {
public static void main(String[] args){
Child b = new Child();
System.out.println(b.str);
b.show();
Base b3 = b;
System.out.println(b3 == b);
System.out.println(b3.str);
b3.show();
}
}
child string
child string
true //因为=就是地址赋值的过程,所以==判断地址相同
base string
child string
- 另外的情况:
String str1 = "hello";
String str2 = "he" + new String("llo");
System.err.println(str1 == str2);
结果为false,因为str2中的llo是新申请的内存块,所以地址不同
String str1 = "hello";
String str2 = "he" + "llo";
System.err.println(str1 == str2);
结果为true,he和llo拼接后在内存中发现有一个拼接好的hello,所有地址相同
Integer i1 = 20;
Integer i2 = 20 ;
System.out.println(i1 == i2); // true
Integer i3 = 200;
Integer i4 = 200 ;
System.out.println(i3 == i4); // false
原因:Integer i1 = 20; 其实是一个自动装箱的过程,编译器会自动展开成Integer i = Integer.valueOf(20);
详情可以看Integer.valueOf的源代码,可以看到参数的值在IntegerCache.low(默 认-128) 到 IntegerCache.high(默认127)范围内时(比如20),
会从IntegerCache.cache中直接取(此处参考Integer的 内部类IntegerCache的源代码,如果不配置的话,默认是cache存储-128到127的Integer),
所以取到的都是同一个 Integer的对象,因此相同。而200不在-128到127范围内,所以会new 一个新的Integer,故不相同。
int i1=20;
int i2=20;
System.out.println(i1==i2);//true
int i3=200;
int i4=200;
System.err.println(i3==i4);//true
基本类型:i1 开辟了一个内存空间,对于i2来说,jvm先在内存中寻找是否有20的地址,有就给i2赋值,也就是让i2也指向20那块地址。所以返回的是TRUE.
- ArrayList和Vector的区别
ArrayList和Vector都是集合框架中的类,都实现了List接口,结构相似
ArrayList为JDK1.2效率高,线程不安全
Vector为JDK1.0效率低,线程安全 - try...catch...finally
一般情况下(try没有异常并且没有调用System.exit()),不管try里面有没有出现异常,finally都是会执行的;当try和catch中有return时,finally仍然会执行,finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以函数返回值是在finally执行前确定的(如果在finally里面再去修改返回的变量的值是没有用的,所以finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值)。
特殊情况:try里面没有异常,并且调用了System.exit(),那么就不会执行到finally块里面。
(关于System.exit(),是将虚拟机停止:
(1)如果对于非入口函数来说,return是返回上一层调用函数继续执行,System.exit()是将整个程序停掉);
(2)对于main方法来说,又分为以下两种:(a)只有主程序一个线程(主程序里面没有启动其他线程),那么加不加System.exit()都是一样的,main运行到最后都是会将整个程序结束的。(b)如果main里面启动了线程,那么在main最后调用System.exit()时会出现子线程没有执行完就被中断的情况。