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

时间:2023-03-08 23:09:48
《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!