《Thinking in Java》学习笔记(六)

 1.Class相关知识

  Class类可以理解为类的图纸,通过Class类可以分析类的结构、构建出类的实例。

  Class.forName("test.TestClass").newInstance()方法要求类test.TestClass必须有一个无参的构造函数,否则会报错。

  Class.forName(test.TestClass)会将类test.TestClass加载到JVM中,并完成初始化的工作,类中的静态方法会执行。

  Class c = Class.forName(test.TestClass);中Class.forName方法返回的Class有一些常用的方法返回Class的信息,如下:

package rtti;
 
import java.util.ArrayList;
import java.util.Arrays;
 
public class ClassInfoTest {
 
 public static void main(String[] args) throws InstantiationException, IllegalAccessException {
  try {
   /*Class clazz = Class.forName("rtti.BenzCar");
   System.out.println("simple name: " + clazz.getSimpleName());
   System.out.println("canonical name: " + clazz.getCanonicalName());
   System.out.println("isInterface: " + clazz.isInterface());
   System.out.println("interfaces: " + Arrays.asList(clazz.getInterfaces()));
   System.out.println("superclass: " + clazz.getSuperclass());*/
   
   //BenzCar.class与Class.forName("rtti.BenzCar")的不同在于不会直接进行类的初始化,而是等到
   //  访问类的静态方法或者成员变量时
   Class<? extends BenzCar> clazz = BenzCar.class;
   System.out.println("test if have load BenzCar class");
   BenzCar car = clazz.newInstance();
   System.out.println(car.getPrice());
   
   if(car instanceof BenzCar){
    System.out.println("car instanceof BenzCar");
   }
   if(car instanceof Car){
    System.out.println("car instanceof Car");
   }
   
   if(clazz.isInstance(car)){
    System.out.println("car isInstance BenzCar");
   }
   
   if(Car.class.isInstance(car)){
    System.out.println("car isInstance Car");
   }
   
   System.out.println(ArrayList.class.isAssignableFrom(Object.class));  //false
      System.out.println(Object.class.isAssignableFrom(ArrayList.class));  //true
 
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
}
 
class Car{}
interface product{}
 
class BenzCar extends Car implements product{
 static{
  System.out.println("Loading BenzCar class");
 }
 
 double price = 12000d;
 
 public double getPrice(){
  return price;
 }
}

  输出结果为:

test if have load BenzCar class
Loading BenzCar class
12000.0
car instanceof BenzCar
car instanceof Car
car isInstance BenzCar
car isInstance Car
false
true

  instanceof和isInstance()方法的作用是完全一致的。

   2.反射相关知识

  Class类与java.lang.reflect下的各类完成了对反射的支持,主要的类包括Field、Method、Constructor等。

  通过反射我们甚至可以调用类的私有方法,构造出一个甚至多个新的单例模式的实例。

package rtti;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;

public class ReflectTest {

    public static void main(String[] args) {
        Class<?> demo = null; 
        try{ 
            demo = Class.forName("rtti.Person");  // = Person.class, = Person.getClass()
        }catch (Exception e) { 
            e.printStackTrace(); 
        } 
        Person per1 = null; 
        Person per2 = null; 
        Person per3 = null;
        //取得全部的构造函数 
        Constructor<?> cons[]  =  demo.getConstructors(); 
        try{ 
            per1 = (Person)cons[0].newInstance(); 
            per2 = (Person)cons[1].newInstance("Rollen",20); 
            per3 = Person.class.newInstance();   //Person.class.newInstance("Rollen",20); error
        }catch(Exception e){ 
            e.printStackTrace(); 
        } 
        System.out.println(per1); 
        System.out.println(per2); 
        System.out.println(per3); 
        
        System.out.println("interface of which Person Class implements: " + Arrays.asList(Person.class.getInterfaces()));
        System.out.println("super class of Person Class: " + Person.class.getSuperclass().getSimpleName());
        //获取方法
        Method[] methods = Person.class.getDeclaredMethods(); //getMethods() will get superclass's method
        for(Method method:methods){
            String modifier = Modifier.toString(method.getModifiers());
            String returnType = method.getReturnType().getSimpleName();
            String methodName = method.getName();
            Class [] excepts = method.getExceptionTypes();

            Class [] clazzs = method.getParameterTypes();
            StringBuffer params = new StringBuffer("");
            for(Class clazz:clazzs){
                params.append(clazz.getSimpleName()).append(",");
            }           
            String param = "";
            if(params.length() > 1){
                param = params.substring(0, (params.length()-1));
            }
            System.out.println(modifier + " " + returnType + " " + methodName + "(" + param + ")" +
                    " " + (excepts.length == 0 ? "" :"throws " +  excepts[0].getSimpleName()));
        }
        //获取成员变量
        Field [] fields = Person.class.getDeclaredFields();
        for(Field field:fields){
            String modifier = Modifier.toString(field.getModifiers());
            String type = field.getType().getSimpleName();
            String name = field.getName();
            System.out.println(modifier + " " + type + " " +name);           
        }       
        //通过反射调用private方法
        try {
            Person p = Person.class.newInstance();
            //p.getPrivateMethod() error,not visiable
            Method method = Person.class.getDeclaredMethod("getPrivateMethod",null);
            method.setAccessible(true);
            method.invoke(Person.class.newInstance());            
        } catch (Exception e) {
            System.out.println(e);
        } 
        //通过反射给成员变量赋值
        try {
            Field f = Person.class.getDeclaredField("name");
            Person p = Person.class.newInstance();
            f.setAccessible(true);
            f.set(p, "xixi");
            System.out.println(f.get(p));
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        System.out.println(Person.class.getClassLoader().getClass().getName());
    }
}

class Person implements Serializable{ 
    private String name; 
    private int age; 
    public Person() { 
          
    } 

    public Person(String name, int age) { 
        this.age = age; 
        this.name = name; 
    } 
    public void setName(String name) throws IllegalArgumentException { 
         this.name = name; 
    } 
    
    public String getName() { 
        return name; 
    } 
    public int getAge() { 
        return age; 
    } 
    @Override
    public String toString(){ 
        return "["+this.name+"  "+this.age+"]"; 
    } 
    
    private void getPrivateMethod(){
        System.out.println("this is a private method in Person Class");
    }
} 

  输出结果为:

[null  0]
[Rollen  20]
[null  0]
interface of which Person Class implements: [interface java.io.Serializable]
super class of Person Class: Object
public String toString() 
public String getName() 
public void setName(String) throws IllegalArgumentException
private void getPrivateMethod() 
public int getAge() 
private String name
private int age
this is a private method in Person Class
xixi
sun.misc.Launcher$AppClassLoader

  需要注意的是,类的Class在JVM中只有一份,我们通过反射将方法的修饰符由private改为了public,后面代码中这个方法的修饰符都将是public。

    我们还可以使用反射来实现工厂模式,代码如下:

  

package rtti;

public class UseReflectForFactoryPattern {

    public static Fruit getCertainFruit(String fruitName){
        Fruit f = null;
        try {
            f = (Fruit) Class.forName(fruitName).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        } 
        return f;
    }
    
    public static void main(String[] args) {
        //这里使用的是完整的类型rtti.Apple,实际使用中可能只会知道类名,比如Apple
        //可以新建properties文件,存储Apple和rtti.Apple的对应关系
        Fruit f = getCertainFruit("rtti.Apple");
        f.eat();
        f = getCertainFruit("rtti.Orange");
        f.eat();
    }
}
interface Fruit{public  abstract void eat();}

class Apple implements Fruit{
    @Override
    public void eat() {
        System.out.println("eat Apple!");
    }    
}

class Orange implements Fruit{
    @Override
    public void eat() {
        System.out.println("eat Orange!");
    }    
}

 3.动态代理基础

  Java中的Proxy类和InvocationHandler提供了动态代理的功能,动态代理还是利用了反射,在原Class的基础上重新生成了一个新的Class,从而可以对目标方法做一些操作。

  Java的动态代理要求被代理的类必须继承了接口,如果被代理的类没有继承了接口,可以可虑用cglib来完成。

  下面是一个Proxy类和InvocationHandler完成动态代理的例子。

package rtti;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JDKRroxy implements InvocationHandler{
    private Object obj;
    
    public Object bind(Object obj){
        this.obj = obj;
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj 
                .getClass().getInterfaces(), this);
    }
    
    public static void main(String[] args) {
        JDKRroxy jr = new JDKRroxy();
        test t =  (test) jr.bind(new ActiveTest()); //error: ActiveTest at =  (ActiveTest) jr.bind(new ActiveTest());        
        t.testMethod();
    }

    @Override
    public Object invoke(Object paramObject, Method method, Object[] args) throws Throwable {
        System.out.println("before method!");
        Object temp = method.invoke(this.obj, args); 
        System.out.println("after method!");
        return temp;
    }

}

interface test{public abstract void testMethod();}
//use JDK Proxy must implements interface
class ActiveTest implements test{
    public void testMethod(){
        System.out.println("this is a test method!");
    }
}
//use cglib,see :http://www.cnblogs.com/lnlvinso/p/4240350.html

  输出结果为:

before method!
this is a test method!
after method!

  

原文地址:https://www.cnblogs.com/lnlvinso/p/4513384.html