1. 基础特性
1) 面向对象
面向对象是一种编程思想,是使用类或对象作为组织代码的基本单元,具有继承、封装、多态三大特性。
继承用来表示类之间的关系,主要作用就是实现代码复用。
封装就是控制类的访问权限,只开放出对外的方法,并抽象出接口类,供使用者操作。一方面,让数据更安全,另一方面,也提高了易用性。
多态简单说就是子类替换父类,或者实现类代替接口类。多态提高了代码的可拓展性和复用性,一方面,在定义方法时可以使用父类型作为参数,调用时使用子类传入,那么多个子类可以使用一个方法,提高了复用性。另一方面,当我们想增加新的子类时,只需继承父类,之前的方法都可以使用,增强了可拓展性,也满足了开闭原则(对拓展开放,对修改关闭)。
2) 重载和重写
重载和重写是面向对象多态性的体现,重载指的是同一个类中的同名方法可以根据不同的参数列表来区分,重写也称覆写,指的是子类可以重写父类的方法。
在Java中,重载是在编译期确定的,下面的例子可以说明,在编译期,编译器并不知道对象的实际类型,所以在调用方法的时候通过静态类型判断来选择重载的方法。
public void sayHello(Human guy) {
System.out.println("guy say hello");
}
public void sayHello(Man man) {
System.out.println("man say hello");
}
public void sayHello(Woman woman) {
System.out.println("woman say hello");
}
public static void main(String[] args) {
// Man和Woman继承了Human
Human man = new Man();
Human woman = new Woman();
StaticDispatch sd = new StaticDispatch();
sd.sayHello(man); // guy say hello
sd.sayHello(woman);// guy say hello
sd.sayHello((Man)man);// man say hello
sd.sayHello((Woman)woman);// woman say hello
}
重写是在运行期确定的,通过下面的例子可以看到。首先根据编译期的重载,两个方法选择了Father.hardChoice(_360());
Father.hardChoice(QQ()); 。在运行时,虚方法表中存放着各个方法的实际入口地址,如果没有重写,子类的方法表中方法的地址就是父类方法表中方法的地址,重写之后子类的方法表中方法的地址就会替换为子类重写的方法的地址。所以在运行期,Son的方法表指向的是Son.hardChoice(QQ());
public class Dispatch {
static class QQ{}
static class _360{}
public static class Father{
public void hardChoice(QQ arg) {
System.out.println("father choose qq");
}
public void hardChoice(_360 arg) {
System.out.println("father choose 360");
}
}
public static class Son extends Father{
@Override
public void hardChoice(QQ arg) {
System.out.println("son choose qq");
}
@Override
public void hardChoice(_360 arg) {
System.out.println("son choose 360");
}
}
public static void main(String[] args) {
Father father = new Father();
Father son = new Son();
father.hardChoice(new _360()); // father choose 360
son.hardChoice(new QQ());// son choose qq
}
}
2. 八种类型
1)基本类型
虽然Java宣称完全面向对象,但是他还是有8种基本类型,为了照顾性能。
1、byte: 8位,最大存储数据量是255,存放的数据范围是-128~127之间。
2、short: 16位,最大数据存储量是65536,数据范围是-32768~32767之间。
3、int: 32位,最大数据存储容量是2的32次方减1,数据范围是负的2的31次方到正的2的31次方减1。
4、long: 64位,最大数据存储容量是2的64次方减1,数据范围为负的2的63次方到正的2的63次方减1。
5、float: 32位,数据范围在3 4e 45~1 4e38,直接赋值时必须在数字后加上f或F。
6、double: 64位,数据范围在4 .9e-324~1 .8e308,赋值时可以加d或D也可以不加。
7、boolean: 只有true和false两个取值。
8、char: 16位,存储Unicode码,用单引号赋值。
2)装箱拆箱
Java对于每种基本类型,都有对应的包装类型,来适应面向对象的思想,方便和其他类进行交互。装箱就是int 转化成 Integer 等等。反之就是拆箱。
原始类型:boolean、char、byte、short、int、long、float、double
封装类型:Boolean、Character、Byte、Short、Integer、Long、Float、Double
装箱和拆箱其实是一种语法糖,是Java在编译期自动完成的,并不需要程序员做什么额外的工作。从代码上来讲就是调用valueOf方法。
3)包装类的缓存
我们看Integer的valueOf方法。可以看到,如果在low和high之间,就会从缓存中取。在IntegerCache的静态代码块中,将缓存存放到Integer[] cache中。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
不止Integer,其他的包装类也有缓存。
Boolean:全部缓存
Byte:全部缓存
Character:<= 127 缓存
Short:-128 — 127 缓存
Long:-128 — 127 缓存
Integer:-128 — 127 缓存
Float和Double没有缓存