数据类型转换小记
Java中有基本数据类型和引用数据类型两大类,两种类型各自有自己的转换规则
基本数据类型
- 种类:byte、short、int、char、float、long、double
- 转换规则如下图所示(实线为合法转换,虚线为强制转换,强制转换有可能引起精度损失),可总结为:
- 两个数值进行二元操作时,先要将两个操作数转换为同一类型(无论是强制的还是自动的)
PS:赋值语句也是二元操作
- 小的向大的转换是自动转换,大的向小的转换需要强制转换
-
float类型的数值有一个后缀f,没有后缀f的浮点数默认为double类型
- 两个数值进行二元操作时,先要将两个操作数转换为同一类型(无论是强制的还是自动的)
public class OperationTrans {
public static void main(String[] args) {
byte a = 10; // byte取值范围是 -128~127
// byte aMinus = -1 * a; // 编译出错除非强转
int aMinusInt = -1 * a; // 赋值语句也是a
long aMinusLong = -1 * a; // 这里会有自动转型
System.out.println(aMinusInt);
System.out.println(aMinusLong);
float b = 10; // 会自动向上转型
int bInt = (int) b; // 需要强转才能装进去, 会造成精度损失
System.out.println(b);
System.out.println(bInt);
float c = 10.5f; // 要特别标注f才能赋给float不写的话默认是double
int cInt = (int) c; // 需要强转才能装进去, 会造成精度损失
System.out.println(c);
System.out.println(cInt);
}
}
引用类型转换
- 包括向上转换(父类引用指向子类实例)和向下引用(类似于强制转换)
- 要点:
- 静态方法不能重写,可以重新定义
- 父类引用指向子类实例时(向上转型是自动的) 比如 Animal dog = new Dog();
- JVM只能“查到”父类所列举的成员方法,比如Dog中有个Animal中没有的bark()方法,会抛出异常
- 调用成员方法时,子类有重写的话,会调用子类重写的方法
- 向下转型(强制),可以“查到”并调用子类中的方法
- 重写:两同两大一小(参数列表、函数名相同;返回类型和访问控制符大;抛出的异常不能比父类小)
public class DogTest {
public static void main(String[] args) {
Animal dog = new Dog(); // 向上转型
dog.eat(); // 父类会调用对象的实例方法
dog.hello(); // 这里会运行父类的静态方法
// dog.finalTest(); // 这里会出现编译错误
// dog.swim(); // 这里会出现编译错误
// 向下转型
((Dog)dog).swim(); // 因为向下转型了,所以可以“查到”子类的方法
((Dog)dog).hello(); // 子类引用调用子类的静态方法
((Dog)dog).finalTest(); // 子类引用
System.out.println(dog.getClass());
Dog dog2 = (Dog)new Animal();
dog2.eat(); // 这里会运行时出错,因为Animal中根本没有eat的方法
}
}
class Animal {
public void eat() {
System.out.println("动物吃饭");
}
// 静态方法不可以重写(静态的东西不存在多态),但是子类中可以重新定义,实际上父类的和子类的是完全不一样的东西
public static void hello() {
System.out.println("HelloAnimal");
}
private final void finalTest() {
System.out.println("I am final");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("狗吃饭");
}
public void swim() {
System.out.println("狗游泳");
}
public static void hello() {
System.out.println("HelloDog");
}
public void finalTest() { //final方法不能被重写,除非是private
System.out.println("I am final");
}
}
- 原理:
为类在方法区中建立一个虚方法表,虚方法表中存放着各个方法的实际入口地址,如果某个方法在子类中没有被重写,那子类的虚方法表里面的地址入口和父类相同方法的入口地址是一致的,都指向父类的实现入口。如果子类重写了这个方法,子类方法表中的地址将会替换为指向子类实现版本的入口地址。
public class DogTest {
public static void main(String[] args) {
Animal dog = new Dog(); // 向上转型
dog.eat(); // 父类会调用对象的实例方法
dog.hello(); // 这里会运行父类的静态方法
// dog.finalTest(); // 这里会出现编译错误
// dog.swim(); // 这里会出现编译错误
// 向下转型
((Dog)dog).swim(); // 因为向下转型了,所以可以“查到”子类的方法
((Dog)dog).hello(); // 子类引用调用子类的静态方法
((Dog)dog).finalTest(); // 子类引用
System.out.println(dog.getClass());
Dog dog2 = (Dog)new Animal();
dog2.eat(); // 这里会运行时异常,因为Animal中根本没有eat的方法
}
}
class Animal {
public void eat() {
System.out.println("动物吃饭");
}
// 静态方法不可以重写(静态的东西不存在多态),但是子类中可以重新定义,实际上父类的和子类的是完全不一样的东西
public static void hello() {
System.out.println("HelloAnimal");
}
private final void finalTest() {
System.out.println("I am final");
}
}
class Dog extends Animal {
public void eat() {
System.out.println("狗吃饭");
}
public void swim() {
System.out.println("狗游泳");
}
public static void hello() {
System.out.println("HelloDog");
}
public void finalTest() { //final方法不能被重写,除非是private
System.out.println("I am final");
}
}