下面来介绍一下Java的高级应用有哪些。
Java高级应用
第一讲 类加载
(一).类加载
类加载器是一个特殊的类,负责在运行时寻找和加载类文件。Java允许使用不同的类加载器,甚至是自定义类加载器。Java程序包含很多类文件,每一个都与单个Java类相对应,这些类文件随时需要随时加载。类加载器从源文件(通常是.class或.jar文件)获得不依赖平台的字节码,然后将它们加载到JVM内存空间,所以它们能被解释和执行。默认状态下,应用程序多的每个类由java.lang.ClassLoader加载。因为它可以被继承,所以可以自由地加强其功能。
1.1 认识Class
Java程序在运行时,运行时系统一直对所有的对象进行运行时类型标识,这项信息记录了每个对象所属的类。JVM通常使用运行时类型信息定位正确方法去执行,用来保存这些类型信息的类是Class类。Class类封装一个对象和接口运行时的状态,当装载类时,Class类型的对象自动创建。
JVM为每种类型管理一个独一无二的Class对像,即每个类(型)都有一个Class对象。运行程序时,JVM首先检查所要加载的类对应的Class对象是否已经加载,如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。
Class无公共构造方法,其对象是在加载类时由JVM以及通过调用类加载器中的defineClass方法自动构造的,因此不能显示地声明一个Class对象。每个类都有一个class属性,可以直接以类.class方式访问,也可以通过实例访问,但实例获得class对象必须要调用getClass()方法才可以。
1.2 Class类的方法
static Class forName(String name)————返回指定类名的Class对象(注意静态的)
Object newInstance()————调用缺省构造方法,返回该Class对象的一个实例
getName()————返回此Class对象所表示的实体(类、接口、数组、基本类型或void)名称
Class []getInstance————获取当前Class对象的接口
ClassLoader getClassLoader()————返回该类的加载器
Class getSuperclass()————返回表示此Class所表示的实体的超类的Class
1.3 实践
下面通过继承关系演示Class类的使用,首先定义Person类及其子类Student类。
1 package com.itsuper.p1.classdemo; 2 public class Person { 3 String name; 4 //如果使用Class的newInstance()构造对象,则需要提供缺省的构造方法 5 public Person() { 6 7 } 8 public Person(String name) { 9 this.name = name; 10 } 11 }
1 package com.itsuper.p1.classdemo; 2 public class Student extends Person { 3 int age; 4 public Student() { 5 6 } 7 public Student(String name, int age) { 8 super(name); 9 this.age = age; 10 } 11 }
编写测试代码,使用Class类实现Student对象的创建
1 package com.itsuper.p1.classdemo; 2 3 public class ClassDemo { 4 5 /** 6 * 演示Class类 7 * @param args 8 */ 9 public static void main(String[] args) { 10 String className = "com.itsuper.p1.classdemo.Student"; 11 //因为调用forName()方法可能抛出异常,需要放到try中 12 try { 13 //调用静态方法forName()获取字符串对应的Class对象 14 Class c1 = Class.forName(className); 15 //构造一个对象,但是相应的构造类中必须提供缺省的构造函数,才能使用Class类的缺省构造方法 16 Object obj = c1.newInstance(); 17 //通过类.class,获取Class实例 18 System.out.println(Student.class); 19 //通过具体对象,获取Class实例,但具体对象获取Class实例必须调用getClass()方法 20 System.out.println(obj.getClass().getName()); 21 //判断类.class 与 具体对象获取Class实例是否是统一引用地址 22 if(obj.getClass()==Student.class){ 23 System.out.println("The Class is Student class!"); 24 } 25 System.out.println("----------------"); 26 27 //获取当前Class对象的父类Class对象 28 Class superClass = c1.getSuperclass(); 29 Object obj2 = superClass.newInstance(); 30 System.out.println(obj2.getClass().getName()); 31 32 //继续获取父类的Class对象 33 Class furtherClass = superClass.getSuperclass(); 34 Object obj3 = furtherClass.newInstance(); 35 System.out.println(obj3.getClass().getName()); 36 37 } catch (Exception e) { 38 // TODO Auto-generated catch block 39 e.printStackTrace(); 40 } 41 } 42 }
运行结果:
class com.itsuper.p1.classdemo.Student com.itsuper.p1.classdemo.Student The Class is Student class! ---------------- com.itsuper.p1.classdemo.Person java.lang.Object
注意: 调用Class.froName(name)方法时,由于指定的类名可能不存在,需要将其放到try...catch语句块中
JVM为每种类型管理一个独一无二的Class对象。因此可以使用==操作符来比较类对象。通过运行结果分析,可以确定obj.getClass()和Student.class事实上是JVM管理的同一个Class对象。
第二讲 ClassLoader
(二). 认识ClassLoader
类装载器是用来把类(class)装载进JVM的。JVM规范定义了两种类型的类装载器:启动内装载器(bootstap)和用户自定义装载器(user-defined class loader).
自底向上检查类是否已装载 |
Bootstap Classloader | 自顶向下尝试加载类 |
Extension Classloader | ||
System Classloader |
Bootstap(启动类加载器)是JVM自带的类装载器,负责装载Java平台核心类库,如java.lang.*等,在Java中看不到他,是null
Extension(扩展类加载器) 主要负责jdk_home/lib/ext目录下的jar包或—Djava.ext.dirs指定目录下的jar包装入工作
System(系统类加载器) 主要负责java-classpath/-Djava.class.path所指定的目录下的类与jar包装入工作
java提供了抽象类ClassLoader,所有用户自定义类装载器都实例化自ClassLoader的子类。ClassLoader是一个特殊的用户自定义类装载器,有JVM的实现者提供,如不特殊指定,其将作为系统缺省的装载器。
实践:
代码演示类加载机制的层次关系
1 public class ClassLoaderDemo { 2 public static void main(String[] args){ 3 ClassLoader classloader; 4 classloader = ClassLoader.getSystemClassLoader(); 5 System.out.println(classloader);//sun.misc.Launcher$AppClassLoader@1016632 6 7 while(classloader!=null){ 8 classloader = classloader.getParent(); 9 System.out.println(classloader);//sun.misc.Launcher$ExtClassLoader@dc6a77 10 // null 11 }//此过程在自底向上判断类加载器 12 13 try{ 14 Class c1 = Class.forName("java.lang.Object");//返回Object的对象 15 classloader = c1.getClassLoader();//获得该对象的类加载器 16 System.out.println("java.lang.Object`s loader is " + classloader); 17 c1 = Class.forName("com.itsuper.p1.classdemo.ClassLoaderDemo"); 18 classloader = c1.getClassLoader(); 19 System.out.println("ClassLoaderDemo`s loader is " + classloader); 20 }catch (Exception e) { 21 System.out.println("Check name of the class"); 22 } 23 } 24 }
运行结果:
sun.misc.Launcher$AppClassLoader@1016632 //表示系统类加载器实例化自sun.misc.Launcher$AppClassLoader sun.misc.Launcher$ExtClassLoader@dc6a77 //表示系统类装载器的parent实例化自类sun.misc.Launcher$ExtClassLoader null //表示系统类加载器的parent的parent为bootstap,无法直接获取 java.lang.Object`s loader is null //表示类Object是由bootstap装载的 ClassLoaderDemo`s loader is sun.misc.Launcher$AppClassLoader@1016632 //表示用户自己写的类是由系统类装载器装载的
2.1 加载过程
ClassLoader加载类时,首先检查缓存中是否有该类
(1) 若有直接返回
(2) 若无,请求父类加载
(3) 如果父类无法加载,则从bootstap classLoader加载
然后加载指定类,搜索的顺序是:
(1) 寻找class文件(从与此classloader相关的类路径中寻找)
(2) 从文件载入class
(3) 找不到则抛出ClassNotFoundException
第三讲 instanceof
(三). 认识instanceof运算符
Java的多态性机制导致了引用变量的声明类型和其实际引用的类型可能不一致,在结合动态方法调度机制可以得出结论:声明为同种类型的两个引用变量调用同一个方法时也可能会有不同的行为。为更准确的鉴别一个对象的真正类型,Java语言引入了instanceof操作符。
3.1 定义
instanceof关键字是用于判断一个引用类型变量所指向的对象是否是一个类(或接口、抽象类、父类)的实例。
3.2 使用格式
<引用类型变量> instanceof <引用类型>
注意:该表达式为Boolean类型的表达式,当instanceof左侧的引用类型变量所引入对象的实际类型是其右侧给出的类型或是其子类类型时,整个表达式的结果为true,否则为false。例如mi instanceof MyClass。
3.3 补充
- 子类对象 instanceof 父类,返回true
- 父类对象 instanceof 子类,返回false
- 如果两个类不在同一继承家族中,是用instanceof时会出现错误
- 数组类型也可以使用instanceof来比较
3.4 实践1
下面通过继承关系来演示instanceof关键字的使用
1 public class InstanceofDemo { 2 3 public static void typeof(Object obj) { 4 if(obj instanceof Student){ 5 System.out.println("Student!"); 6 } 7 if(obj instanceof Person){ 8 System.out.println("Person!"); 9 } 10 } 11 public static void main(String[] args) { 12 Person pobj1 = new Person("tom"); 13 Student sobj1 = new Student("Daming",5); 14 typeof(pobj1); 15 System.out.println("-------------------"); 16 typeof(sobj1); 17 System.out.println("-------------------"); 18 Person pobj2 = new Person("rose"); 19 Student sobj2 = new Student("xiaoli",10); 20 typeof(pobj2); 21 System.out.println("-------------------"); 22 typeof(sobj2); 23 System.out.println("-------------------"); 24 String[] str = new String[2]; 25 if(str instanceof String[]){ 26 System.out.println("true! "); 27 } 28 } 29 }
运行结果:
Person! ------------------- Student! Person! ------------------- Person! Student! Person! ------------------- true!
通过对比结果,有什么发现呢?再仔细的品味一下 这句话吧! “instanceof左侧的引用类型变量所引入对象的实际类型是其右侧给出的类型或是其子类类型时,整个表达式的结果为true”
实践2
定义一个接口IBase和两个类Derive,Derive1来演示instanceof用法
1 //定义Interface接口IBase 2 interface IBase{ 3 public void print(); 4 } 5 6 //定义Derive类实现IBase接口 7 class Derive implements IBase{ 8 int b; 9 public Derive(int b) { 10 super(); 11 this.b = b; 12 } 13 //实现接口的抽象方法 14 public void print(){ 15 System.out.println("In Derive!"); 16 } 17 } 18 19 //定义Derive的子类Derive1 20 class Derive1 extends Derive{ 21 int c; 22 public Derive1(int b, int c) { 23 super(b); 24 this.c = c; 25 } 26 public void print(){ 27 System.out.println("In Derive1!"); 28 } 29 } 30 31 public class InstanceDemo2 { 32 //判断对象类型 33 public static void typeof(Object obj){ 34 if(obj instanceof Derive){ 35 Derive der = (Derive)obj; 36 der.print(); 37 }else if(obj instanceof Derive1){ 38 Derive1 der1 = (Derive1)obj; 39 der1.print(); 40 } 41 } 42 43 public static void main(String[] args) { 44 IBase b1 = new Derive(4);//父类引用指向子类对象 45 IBase b2 = new Derive1(4,5); 46 System.out.print("b1 is "); 47 //调用typeof()判断b1对象类型 48 typeof(b1); 49 System.out.print("b2 is "); 50 //调用typeof()判断b2对象类型 51 typeof(b2); 52 } 53 }
运行结果:
b1 is In Derive! b2 is In Derive1!