采用 abstract 方法的类本来就是抽象类,并且必须声明为 abstract。
abstract 类不能实例化。
仅当 abstract 类的子类实现其超类的所有 abstract 方法时,才能实例化 abstract 类的子类。这种类称为具体类,以区别于 abstract 类。
如果 abstract 类的子类没有实现其超类的所有 abstract 方法,该子类也是 abstract 类。
abstract 关键字不能应用于 static、private 或 final 方法,因为这些方法不能被重写,因此,不能在子类中实现。
final 类的方法都不能是 abstract,因为 final 类不能有子类。
类的定义方式不同,抽象类用class,接口用interface
继承方式不同,抽象类是单继承,使用关键字extends;接口是多实现的,使用关键字implements。
接口中的属性,必须是public修饰的常量;抽象类随意。
抽象类中可以有抽象方法,也可以没有;接口中的方法一定是public abstract的。抽象类一定有构造方法,但是不能new对象,该构造是为了子类的调用;接口中没有构造方法的存在。
接口具有强制性,其方法必须被实现类重写;抽象类没有。
定义规范:最好使用接口。
抽象类的作用不在于创建对象(也不能创建),而在于被继承。
其子类必须重写父类的所有抽象方法,否则也会被定义为抽象类。可以说,抽象类,对其实现类的代码提供了强制性和规范性(模板设计模式便是源于此)。
三种方式
运行时通过new方式载入。 如:Dog dog = new Dog();
通过反射加载类,并创建对象实例。 如: Class clazz = Class.forName(“Dog”); Object dog = clazz.newInstance();
调用某个ClassLoader实例的loadClass()方法。 如:Class clazz = ClassLoader.loadClass(“Dog”); Object dog = clazz.newInstance();
区别
第一种和第二种方式使用的类加载器是相同的,都是当前类的类加载器( this.getClass().getClassLoader() );第三种方式用的类加载器是用户指定的,其加载的类与当前类加载器加载的类属于不同命名空间。
第一种是静态加载;第二种和第三种是动态加载。
Class的装载包括3个步骤:加载(loading),连接(link),初始化(initialize).
Class.forName(className)实际上是调用Class.forName(className, true, this.getClass().getClassLoader())。第二个参数,是指Class被loading后是不是必须被初始化。
ClassLoader.loadClass(className)实际上调用的是ClassLoader.loadClass(name, false),第二个参数指Class是否被link。
Class.forName(className)装载的class已经被初始化,而ClassLoader.loadClass(className)装载的class还没有被link。一般情况下,这两个方法效果一样,都能装载Class。但如果程序依赖于Class是否被初始化,就必须用Class.forName(name)了。
例如,在JDBC编程中,常看到这样的用法,Class.forName(“com.MySQL.jdbc.Driver”).如果换成getClass().getClassLoader().loadClass(“com.mysql.jdbc.Driver”),就不行。 com.mysql.jdbc.Driver的源代码如下:
// Register ourselves with the DriverManager static { try { Java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } }原来,Driver在static块中会注册自己到java.sql.DriverManager。而static块就是在Class的初始化中被执行。 所以这个地方就只能用Class.forName(className)。
对于相同的类,JVM最多会载入一次。但如果同一个class文件被不同的ClassLoader载入,那么载入后的两个类是完全不同的。因为已被加载的类由该类的类加载器实例与该类的全路径名的组合标识。设有 packagename.A Class ,分别被类加载器 CL1 和 CL2 加载,所以系统中有两个不同的 java.lang.Class 实例:
new Dog();
clazz.newInstance();或者 clazz.getConstuctor(…).newInstance(…);
Object.clone();//通过本地方法进行克隆
反序列化
JVM去磁盘中寻找class文件,读入内存。
进行类的加载,先加载父类再加载子类;同时分配static属性的内存空间,执行static语句块。
给父类和子类的非静态属性分配内存空间,清空属性或清0.
执行父类的属性初始化语句(如果有属性有赋值那么就初始化该值,否则还是空或者0);
执行父类的语句块
执行父类构造
执行子类的属性初始化语句(如果有属性有赋值那么就初始化该值,否则还是空或者0);
执行子类的语句块
执行子类构造