java 日常笔记
编译时类型,运行时类型
编译时类型仅仅由变量定义时的声明类型所决定。
运行时类型由引用实际所指对象的类型所决定。
Object obj = "abc";//此处的obj编译类型是Object,运行时类型为String
Number num = new Integer("12");//此处的num编译类型是Number,运行时类型为Integer
instance of
A instance of B 返回true或false
A是一个对象实例,可以为null,B是一个类、接口(要求A和B有继承关系或实现关系)
如果A的运行时类型是类B的实例,接口B的实例,类B的子类的实例,返回true。
当A是null,则一定会返回false;
- 对A的编译时类型的要求(通过编译的要求)
A是类B、类B的子类、类B的父类的实例(简言之,A的编译时类型和B必须存在继承、实现关系,才能通过编译)
使用总结:
- A的编译时类型和B存在继承实现关系,才可以通过编译。
- 运行时返回的结果,A的运行时类型是B本身,B子类的实例,返回true。特别的A运行时为null,返回false。
例子:
String str = "abc";
System.out.println(str instanceof Integer);//String和Integer不存在继承实现关系,编译不通过
System.out.println(str instanceof Object);//返回true
Object obj = "abc";//此处的obj编译类型是Object,运行时类型为String
System.out.println(obj instanceof String);//obj运行时类型是String,返回true
System.out.println(obj instanceof Integer);//obj运行时类型是String,返回false
System.out.println( null instanceof Object );//返回false
使用场景
- 在类型转换之前先instanceof一下
在类型转换之前使用instanceof 判断,保证某个对象时某个类的实例或子类的实例,同时保证对象不是null(避免运行时抛出空指针异常)。
Object obj1 = "12345";
if(obj1 instanceof String) {
String str1 = (String)obj1;
System.out.println("str1"+str1.toString());
}
Object obj2 = null;
if(obj2 instanceof String) {
String str2 = (String)obj2;
System.out.println("str2"+str2.toString());
}
//结果:str112345
强制类型转换
(A)B
A是一个类,B是一个对象。
例子:
Object obj = "123";
String str =(String)obj;
使用总结
- A和B 的编译时类型存在继承关系,才可以通过编译。(A是对象B本身代表的类,B的子类,B父类)
- 在运行阶段,对象B的运行时类型必须和类A完全一致。否则会在运行时抛出异常ClassCastException。
- 例子
向下转型
(子类)父类的对象 //父类的对象的运行时类型必须和子类完全一致。
eclipse在保存后会自动编译,编译不通过会出现红叉,强制运行会抛出异常。
构造器的陷阱
构造方法的 返回值 不需要写任何东西。
如果写了包括void,int,String等等任何的类型, 此构造函数将变成 普通的实例方法。
java中创建对象的4种方式
1. 通过**new** 类名(参数), 调用构造函数,创建。(注意构造函数仅仅执行赋值操作)
分配内存,调用构造函数 赋值。
2. 通过**反射** 调用构造函数 创建对象。
实质还会调用构造函数。
3. 通过反序列化,从文件读取一个对象。让对象实现Serializable接口,创ObjectOutputStream,FileOutputStream,ObjectInputStream,FileInputStream,
先把一个对象写入文件,再从文件读出对象的信息,在堆中创建一个新的对象。 新的对象的变量值和原对象完全相同,但是两个对象在堆中的地址不同。
4. 通过clone从内存复制一个对象。对象实现Cloneable接口,重写Object clone()方法。
根据内存中已存在的一个对象,在堆中创建一个新的对象。 新的对象的变量值和原对象完全相同,但是两个对象在堆中的地址不同。