布尔型: boolean(1)
字符型: char(2)
整数型: byte(1), short(2), int(4), long(8)
浮点数型: float(4), double(8)
- 对于short s1=1;s1=s1+1来说,在s1+1运算时会自动提升表达式的类型为int,那么将int赋予给short类型的变量s1会出现类型转换错误。
- 对于short s1=1;s1+=1来说 +=是java语言规定的运算符,java编译器会对它进行特殊处理,因此可以正确编译。
int和Integer的区别
1、Integer是int的包装类,int则是java的一种基本数据类型
2、Integer变量必须实例化后才能使用,而int变量不需要
3、Integer实际是对象的引用,当new一个Integer时,实际上是生成一个指针指向此对象;而int则是直接存储数据值
4、Integer的默认值是null,int的默认值是0
int是java的8种基本数据类型之一。Integer是Java为int类型提供的封装类。
int变量的默认值为0,Integer变量的默认值为null,这一点说明Integer可以区分出未赋值和值为0的区别,比如说一名学生没来参加考试,另一名学生参加考试全答错了,那么第一名考生的成绩应该是null,第二名考生的成绩应该是0分。Integer类内提供了一些关于整数操作的一些方法。
对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,则比较结果为true,如果两个变量的值不在此区间,则比较结果为false
Integer i = 100;Integer j = 100;System.out.print(i == j); //true
Integer i = 128;Integer j = 128;System.out.print(i == j); //false
java在编译Integer i = 100 ;时,会翻译成为Integer i = Integer.valueOf(100);,而java API中对Integer类型的valueOf的定义如下:
public static Integer valueOf(int i)
{ assert IntegerCache.high >= 127;
if (i >= IntegerCache.low && i <= IntegerCache.high)
{ return IntegerCache.cache[i + (-IntegerCache.low)]; }
return new Integer(i);
}
java对于-128到127之间的数,会进行缓存,Integer i = 127时,会将127进行缓存,下次再写Integer j = 127时,就会直接从缓存中取,就不会new了
一. 继承的好处和坏处
好处:
- 子类能自动继承父类的接口
- 创建子类的对象时, 无须创建父类的对象
坏处:1. 破坏封装, 子类与父类之间紧密耦合, 子类依赖于父类的实现, 子类缺乏独立性 - 支持扩展, 但是往往以增加系统结构的复杂度为代价
- 不支持动态继承。 在运行时, 子类无法选择不同的父类
- 子类不能改变父类的接口
多态:
多态一般可以分为两种,一个是重写overwrite,一个是重载override。
写是由于继承关系中的子类有一个和父类同名同参数的方法,会覆盖掉父类的方法。重载是因为一个同名方法可以传入多个参数组合。
注意,同名方法如果参数相同,即使返回值不同也是不能同时存在的,编译会出错。
从jvm实现的角度来看,重写又叫运行时多态,编译时看不出子类调用的是哪个方法,但是运行时操作数栈会先根据子类的引用去子类的类信息中查找方法,找不到的话再到父类的类信息中查找方法。
封装:
封装主要是因为Java有访问权限的控制。public > protected > package = default > private。封装可以保护类中的信息,只提供想要被外界访问的信息。
类的访问范围:
A、public 包内、包外,所有类中可见
B、protected 包内所有类可见,包外有继承关系的子类可见
(子类对象可调用)
C、(default)表示默认,不仅本类访问,而且是同包可。
D、private 仅在同一类中可见
向上转型和向下转型的解释 :
public static void main(String[] args) {
Son son = new Son();
//首先先明确一点,转型指的是左侧引用的改变。
//father引用类型是Father,指向Son实例,就是向上转型,既可以使用子类的方法,也可以使用父类的方法。
//向上转型,此时运行father的方法
Father father = son;
father.smoke();
//不能使用子类独有的方法。
// father.play();编译会报错
father.drive();
//Son类型的引用指向Father的实例,所以是向下转型,不能使用子类非重写的方法,可以使用父类的方法。
//向下转型,此时运行了son的方法
Son son1 = (Son) father;
//转型后就是一个正常的Son实例
son1.play();
son1.drive();
son1.smoke();
```
//因为向下转型之前必须先经历向上转型。
// 在向下转型过程中,分为两种情况:
//
// 情况一:如果父类引用的对象如果引用的是指向的子类对象,
// 那么在向下转型的过程中是安全的。也就是编译是不会出错误的。
//因为运行期Son实例确实有这些方法
Father f1 = new Son();
Son s1 = (Son) f1;
s1.smoke();
s1.drive();
s1.play();
// 情况二:如果父类引用的对象是父类本身,那么在向下转型的过程中是不安全的,编译不会出错,
// 但是运行时会出现java.lang.ClassCastException错误。它可以使用instanceof来避免出错此类错误。
//因为运行期Father实例并没有这些方法。
Father f2 = new Father();
Son s2 = (Son) f2;
s2.drive();
s2.smoke();
s2.play();
//向下转型和向上转型的应用,有些人觉得这个操作没意义,其实可以用于方法参数中的类型聚合,然后具体操作再进行分解。
//比如add方法用List引用类型作为参数传入,传入具体类时经历了向下转型
add(new LinkedList());
add(new ArrayList());
//总结
//向上转型和向下转型都是针对引用的转型,是编译期进行的转型,根据引用类型来判断使用哪个方法
//并且在传入方法时会自动进行转型(有需要的话)。运行期将引用指向实例,如果是不安全的转型则会报错。
//若安全则继续执行方法。
}
public static void add(List list) {
System.out.println(list);
//在操作具体集合时又经历了向上转型
// ArrayList arr = (ArrayList) list;
// LinkedList link = (LinkedList) list;
}
总结:
向上转型和向下转型都是针对引用的转型,是编译期进行的转型,根据引用类型来判断使用哪个方法。并且在传入方法时会自动进行转型(有需要的话)。运行期将引用指向实例,如果是不安全的转型则会报错,若安全则继续执行方法。
编译期的静态分派:其实就是根据引用类型来调用对应方法。
public static void main(String[] args) {
Father father = new Son();
静态分派 a= new 静态分派();
//编译期确定引用类型为Father。
//所以调用的是第一个方法。
a.play(father);
//向下转型后,引用类型为Son,此时调用第二个方法。
//所以,编译期只确定了引用,运行期再进行实例化。
a.play((Son)father);
//当没有Son引用类型的方法时,会自动向上转型调用第一个方法。
a.smoke(father);
//
}
public void smoke(Father father) {
System.out.println("father smoke");
}
public void play (Father father) {
System.out.println("father");
//father.drive();
}
public void play (Son son) {
System.out.println("son");
//son.drive();
}
Java 中是否可以覆盖(override)一个 private 或者是 static 的方法?
Java 中 static 方法不能被覆盖, 因为方法覆盖是基于运行时动态绑定的, 而 static 方法是编译时静态绑定的。 static 方法跟类的任何实例都不相关, 所以概念上不适用。java 中也不可以覆盖 private 的方法, 因为 private 修饰的变量和方法只能在当前类中使用,如果是其他的类继承当前类是不能访问到 private 变量或方法的, 当然也不能覆盖。