以下是从网站 padi.tech学习的笔记:
1、基本类型都对应于一个包装类:每个包装类都有自己的常量池,常量池都有自己的范围,利用包装类创建对象是有两种方法:
Integer x=2; //自动装箱
int m=x; //自动拆箱
常量池:
Integer x = new Integer(123); //new 方法创建对象 (每次都是一个新的地址值)
Integer y = new Integer(123);
sout(x==y) //false
Integer y = Integer.valueOf(123) //valueOf方法(从常量池里找值,给相同的地址)
Integer x = Integer.valueOf(123)
sout(x==y) //true
String类也有自己的常量池:
1、直接创建和new创建是不一样的,直接创建,会先从常量池里面找一下,看是否会有该值,有的话就直接把那个值的引用地址给他。如果没有,就在常量池里面创建后给他。而new一个,会创建出来一个对象,该对象会直接在常量池中被创建出来,也就是说new出来的对象会指向常量池中的地址,而作为对象的指针会指向对象,这两者地址是不同的。
但是若是采用+法,和new另一个值,来拼成所要对象,然后再加上intern方法,就可以实现指向相同。intern会是常量池中的地址等于对象的地址。
2、String的不可变:指的是那个字符串创建后就不可变,是值不可变,而不是指针指向的内容不可变。
Java参数是以值传递的方式,传递的参数的地址,本质上传递的还是指针。
隐式类型转换:低精度转高精度可以直接转,这叫隐式类型转换。
显式类型转换:高精度转低精度需要强制类型转换。
float与double:
float i = 1.1 //会报错
float i = 1.1f //不报错,因为1.1会被认为是double类型,而float精度低,或者加f或者向下转型,即强制类型转换
switch:不支持判断long类型,在Java7之后就开始支持判断字符串类型了。
抽象类和接口:这两个本就很像,现在要区分一下他们两个:抽象类中可以有抽象的东西和非抽象的东西,但是接口必须是抽象的,但在Java8之后,可以实现默认方法,使用default来修饰。
何时使用:抽象类更倾向于在几个相关的类中使用(这几个类中有多个共同的方法,且当成员变量较多时,而且各个修饰符都有时,而不单单是使用public。另外需要继承非静态的方法或变量时。
接口:优点是接口可以多实现,适用于几个关系不大的类,每个类实现那么几个方法。
super:可以用来调用父类的方法和变量,还可以在子类构造方法中调父类构造方法:灵活使用吧:
public class SuperExample {
protected int x;
protected int y;
public SuperExample(int x, int y) {
this.x = x;
this.y = y;
}
public void func() {
System.out.println("SuperExample.func()");
}
}
public class SuperExtendExample extends SuperExample {
private int z;
public SuperExtendExample(int x, int y, int z) {
super(x, y);
this.z = z;
}
@Override
public void func() {
super.func();
System.out.println("SuperExtendExample.func()");
}
}
SuperExample.func()
SuperExtendExample.func()
方法重写与重载的区别:
1.重写:是出现在继承关系里面的,即子类实现了父类中相同的方法
但是要满足里氏替换规则:访问权限更大,返回值相同或是父类返回类型的子类
2.重载:是出现在同一个类中,方法名一样,但至少有一个不同(参数类型,顺序,个数)。
但是如果其他都相同,但是返回值不同,不算重载,即与返回值无关。
Object类通用方法:
1.equals,比对象的内容,而不比对象本身的地址。与 ==不同,如果是引用类型,==比对象是否相同,而不关心值。
equals的内部机制:先比较两个是否为同一个对象 内部使用==,若是,直接true,若不是判断比较的对象是否为空,再判断是否为同一类型(使用getclass比较)若不是返回false;最后比较两者的值是否一样。
2、hashcode():返回散列值对象等价,散列值一定相同,但反之则不成立。散列值我的理解是类似于一个地址的标识,hashset就是以这个值来区别是否相同的。
3、clone():该方法需要类显示重写该方法,才能被调用,且调用的类必须实现Cloneable接口,但是clone()方法是Object里面的方法,接口只是起标识作用。
4、尽量不要使用clone(),而是使用克隆构造函数。
public class CloneConstructorExample {
private int[] arr;
public CloneConstructorExample() {
arr = new int[10];
for (int i = 0; i < arr.length; i++) {
arr[i] = i;
}
}
public CloneConstructorExample(CloneConstructorExample original) {
arr = new int[original.arr.length];
for (int i = 0; i < original.arr.length; i++) {
arr[i] = original.arr[i];
}
}
public void set(int index, int value) {
arr[index] = value;
}
public int get(int index) {
return arr[index];
}
}
CloneConstructorExample e1 = new CloneConstructorExample();
CloneConstructorExample e2 = new CloneConstructorExample(e1);
e1.set(2, 222);
System.out.println(e2.get(2)); // 2
关键字:
1、final :
(1):数据:如果是修饰基本类型则该变量数值不能改变,也可以修饰引用类型,那么就不能引用了。但引用对象里面的变量可以改变。
final int x = 1;
// x = 2; // cannot assign value to final variable 'x'
final A y = new A();
y.a = 1;
(2):方法:方法被修饰后,该方法将不会被重写,子类使用相同的名字也不叫重写。private修饰的方法默认是final。
(3):类:最终类的意思,该类无法被继承
2、static:
(1):静态变量:所有实例共享该变量,静态变量只在地址中存放在一份。而实例变量随着实例创建生成。
(2):静态方法:在类加载的时候就实现了,必须要有方法体,不能为空。
(3):静态语句块:在类初始化时运行一次。
(4):静态内部类:在外部类中不需要外部类引用,而非静态内部类需要:
public class OuterClass {
class InnerClass {
}
static class StaticInnerClass {
}
public static void main(String[] args) {
// InnerClass innerClass = new InnerClass(); // 'OuterClass.this' cannot be referenced from a static context
OuterClass outerClass = new OuterClass();
InnerClass innerClass = outerClass.new InnerClass();
StaticInnerClass staticInnerClass = new StaticInnerClass();
}
}
(5):初始化顺序:静态变量和静态语句块优先于普通变量和普通语句块,静态变量和静态语句块看顺序执行。
如果存在继承:
- 父类(静态变量、静态语句块)
- 子类(静态变量、静态语句块)
- 父类(实例变量、普通语句块)
- 父类(构造函数)
- 子类(实例变量、普通语句块)
- 子类(构造函数)