ThinkInJava_14_类型信息

运行时类型信息可以让你在程序运行时发现和使用类型信息

14.1 为什么需要RTTI

List<Shape> shapeList = Arrays.asList(new Circle(), new Square(), new Triangle()};
for(Shape shape : shapeList)
	shape.draw(); //运行时判断这个对象
//通过RTTI,可以知道某个Shape引用所指向的对象的确切类型

14.2 Class对象

  • 每个类产生一个class对象,并使用“类加载器”子系统
  • 可以包含一条类加载链,但只有一个原生类加载器
  • 所有类都是在对其第一次使用时,动态加载到JVM中的,当程序创建第一个对类的静态引用时,就会加载这个类,构造器也是类的静态方法,所以通过new产生对象时,也会出发类的加载
  • 类加载器首先确定这个类的Class对象是否已经加载,如果尚未加载,默认的类加载器会根据类名查找.class文件
  • Java类仅在用到这个类时才会被加载,没用到不会加载
Class.forName("Shape");
//Class.forName() 是Class类的一个静态方法,
//用以获取一个Class类对象的引用,如果这个类还没有加载就加载这个类,加载过程中,这个类的static成员被执行
catch(ClassNotFoundException e) {}
//找不到类异常
interface HasBatteries {}
interface WaterProof {}
interface Shoots {}
class Toy {
    Toy() {}
    Toy(int i) {}
}
class FancyToy extends Toy implements HasBatteries,WaterProof,Shoots{
    FancyToy() { super(1);}
}
public class ToyTest {
    static void printInfo(Class c) {
        System.out.println("Class name: " + c.getName() +
        " is interface? [" + c.isInterface() + "]");
        System.out.println("Simple name: " + c.getSimpleName());
        System.out.println("Canonical name: " + c.getCanonicalName());

    }
    public static void main(String[] args) {
        Class c = null;
        try {
           c = Class.forName("FancyToy");
           //创建一个Class引用并将其初始化指向FancyToy类
        } catch(ClassNotFoundException e) {

        }
        printInfo(c);
        for(Class face : c.getInterfaces())
            printInfo(face);
        Class up = c.getSuperclass();
        Object obj = null;
        try {
            obj = up.newInstance();
        } catch (InstantiationException e) {
            System.out.println("Cannot instantiate");
        } catch(IllegalAccessException e) {
            System.out.println("Cannot access");
        }
        printInfo(obj.getClass());
    }
}
/*
Class name: FancyToy is interface? [false]
Simple name: FancyToy
Canonical name: FancyToy
Class name: HasBatteries is interface? [true]
Simple name: HasBatteries
Canonical name: HasBatteries
Class name: WaterProof is interface? [true]
Simple name: WaterProof
Canonical name: WaterProof
Class name: Shoots is interface? [true]
Simple name: Shoots
Canonical name: Shoots
Class name: Toy is interface? [false]
Simple name: Toy
Canonical name: Toy
 */
//创建一个Class引用并将其初始化指向FancyToy类
Class c = Class.forName("FancyToy");
//用字面量创建Class对象的引用,在编译时就会受到检查,更加安全
FancyToy.class;
  • 包装器
等价于
boolean.classBoolean.TYPE
char.classCharacter.TYPE
byte.classByte.TYPE
short.classShort.TYPE
int.classInteger.TYPE
long.classLong.TPPE
float.classFloat.TYPE
double.classDouble.TYPE
void.classVoid.TYPE
  • 使用.class来创建Class对象引用时,不会自动初始化该对象,初始化被延迟到了静态成员首次引用时才执行
  1. 加载,由类加载器执行,查找字节码并创建一个Class对象
  2. 链接,验证类中的字节码,为静态区域分配空间
  3. 初始化,如果该类具有超类,则对其初始化,执行静态初始化器和静态初始化块
  • static final 的成员可以看成编译期常量,它不需要对类进行初始化就可以读取,但对仅仅是static的成员的访问需要对类进行强制的初始化
  • Class泛型
Class intClass = int.class;
Class<Integer> genericIntClass = int.class; //泛型的Class对象
genericIntClass = Integer.class;
intClass = double.class; //普通的Class对象可以修改类型
genericIntClass = double.class; //出错,泛型的Class只能赋值为相同类型的对象
Class<?> intClass1 = int.class; //是用了通配符
intClass1 = double.class; //可以使用,因为泛型中添加了通配符
Class<? extends Number> bounded = int.class; //可以为Number类型或任何其子类型
bounded = double.class;
bounded = Number.class;
import java.util.*;

class CountedInteger {
    private static long counter;
    private final long id = counter++;
    public String toString() { return Long.toString(id); }
}
public class FilledList<T> {
    private Class<T> type;
    //通过传入类型,创建该类对象实例
    public FilledList(Class<T> type) { this.type = type; }
    public List<T> create(int nElements) {
        List<T> result = new ArrayList<T>();
        try {
            for (int i = 0; i < nElements; i++)
                result.add(type.newInstance());
                //type.newInstance()将返回确切的类型
        } catch (Exception e) {
            throw new RuntimeException();
        }
        return result;
    }
    public static void main(String[] args) {
        FilledList<CountedInteger> fl =
                new FilledList<CountedInteger>(CountedInteger.class);
        System.out.println(fl.create(15));
    }
}
/*
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
 */
Class< ? super FancyToy> c = Fancy.class.getSuperclass();
Class<Toy> c = Fancy.class.getSuperclass(); //错误
Building b = new House();
Class<House> houseType = House.class;
House h = houseType.cast(b); //转型为Class引用的类型
h = (House)b;

14.3 类型转换前先做检查

  • 三种RTTI的方式
    1)强制类型转换
    2)Class对象获取运行时信息
    3)instanceof
if(x instanceof Dog)
	((Dog)x).bark();
  • instanceof 只能将其与命名的类型进行比较,而不能与Class对象作比较

```java
public static final List<Class<? extends Pet>> allTypes = 
	Colletions.unmodifiableList(Arrays.asList(Pet.class, Dog.class, Rodent.class));
	//这次生成的allTypes不用写在try{}块里,因为这里的类型是在编译期检查的,
	//而不像Class.forName()在运行时才检查
class PetCounter extends LinkedHashMap<Class<? extends Pet>, Integer> {
	public void count(Pet pet) {
		for(Map.Entry<Class<? extends Pets>,Integer> pair : entrySet())
			if(pair.getKey().isInstance(pet) //动态的instanceof语法
				put(pair.getKey(),pair.getValue() + 1);
	}
}
//使用Class实现通用的类计数器
import java.util.*;
public class TypeCounter extends HashMap<Class<?>, Integer> {
    private Class<?> baseType;
    public TypeCounter(Class<?> baseType) {
        this.baseType = baseType;
    }
    public void count(Object obj) {
        Class<?> type = baseType.getClass();
        //运行时检查,检测对象确实是想要的类型
        if(!baseType.isAssignableFrom(type))
            throw new RuntimeException(obj + " incorrect type: "
                    + type + ", should be type or subtype of "
                    + baseType
            );
        countClass(type);
    }
    private void countClass(Class<?> type) {
        Integer quantity = get(type);
        put(type, quantity == null ? 1: quantity + 1);
        Class<?> superClass = type.getSuperclass();
        if(superClass != null && baseType.isAssignableFrom(superClass))
            countClass(superClass);
        //超类递归计数
    }
    public String toString() {
        StringBuilder result = new StringBuilder("{");
        for(Map.Entry<Class<?>,Integer> pair : entrySet()) {
            result.append(pair.getKey().getSimpleName());
            result.append("=");
            result.append(pair.getValue());
            result.append(", ");
        }
        result.delete(result.length()-2,result.length());
        result.append("}");
        return result.toString();
    }
    public static void main(String[] args) {
        
    }
}

14.4 注册工厂

  • 将创建对象的工作交给类自己去完成,工厂方法可以多态地被调用,从而创建恰当类型的对象
public interface Factory<T> { T create(); }
import java.util.*;
interface Factory<T> { T create(); }
class Part {
    public String toString() {
        return getClass().getSimpleName();
    }
    //子类工厂类的List,是静态成员
    static List<Factory<? extends Part>> partFactories
            = new ArrayList<Factory<? extends Part>>();
    //初始化子类工厂类List中的对象
    static {
        partFactories.add(new FuelFilter.FactoryImpl());
        partFactories.add(new AirFilter.FactoryImpl());
        partFactories.add(new CabinFilter.FactoryImpl());
        partFactories.add(new OilFilter.FactoryImpl());
        partFactories.add(new FanBelt.FactoryImpl());
        partFactories.add(new PowerSteeringBelt.FactoryImpl());
        partFactories.add(new GeneratorBelt.FactoryImpl());
    }
    private static Random rand = new Random(47);
    public static Part createRandom() {
        int n = rand.nextInt(partFactories.size());
        //随机选取其中一个Factory对象调用create()
        return partFactories.get(n).create();
    }
}
class Filter extends Part {}
//在子类的内部实现工厂类接口,用工厂类接口创建对象
class FuelFilter extends Filter {
    public static class FactoryImpl
    implements Factory<FuelFilter> {
        public FuelFilter create() { return new FuelFilter(); }
    }
}
class AirFilter extends Filter {
    public static class FactoryImpl
            implements Factory<AirFilter> {
        public AirFilter create() { return new AirFilter(); }
    }
}
class CabinFilter extends Filter {
    public static class FactoryImpl
            implements Factory<CabinFilter> {
        public CabinFilter create() { return new CabinFilter(); }
    }
}
class OilFilter extends Filter {
    public static class FactoryImpl
            implements Factory<OilFilter> {
        public OilFilter create() { return new OilFilter(); }
    }
}
class Belt extends Part {}
class FanBelt extends Belt {
    public static class FactoryImpl
            implements Factory<FanBelt> {
        public FanBelt create() { return new FanBelt(); }
    }
}
class GeneratorBelt extends Belt {
    public static class FactoryImpl
            implements Factory<GeneratorBelt> {
        public GeneratorBelt create() { return new GeneratorBelt(); }
    }
}
class PowerSteeringBelt extends Belt {
    public static class FactoryImpl
            implements Factory<PowerSteeringBelt> {
        public PowerSteeringBelt create() { return new PowerSteeringBelt(); }
    }
}
public class RegisteredFactories {
    public static void main(String[] args) {
        for(int i = 0;i < 10;i++)
            System.out.println(Part.createRandom());
    }
}
/*
GeneratorBelt
CabinFilter
GeneratorBelt
AirFilter
PowerSteeringBelt
CabinFilter
FuelFilter
PowerSteeringBelt
PowerSteeringBelt
FuelFilter
 */

14.5 instanceof与Class的等价性

  • instanceof 检查类也检查这个类的派生类
  • ==和equals()则比较实际的Class对象

14.6 反射:运行时的信息

  • 人们希望在运行时获得类的信息
  • 反射提供了一种机制——用来检查可用的方法,并返回方法名
  • 人们希望在跨网络的远程平台上创建和运行对象,这被称为远程方法调用(RMI)
    1) Construct创建对象
    2) Field, get(), set()
  1. Method, invoke()
  • RTTI 在编译时打开和检查.class文件,而反射在运行时打开和检查.class文件
import java.lang.reflect.*;
import java.util.regex.*;

public class ShowMethods {
    private static Pattern p = Pattern.compile("\\w+\\.");
    public static void main(String[] args) {
        if(args.length < 1) {
            System.exit(0);
        }
        try {
            Class<?> c = Class.forName(args[0]);
            Method[] methods = c.getMethods();
            Constructor[] ctors = c.getConstructors();
            for(Method method : methods) {
                System.out.println(p.matcher(method.toString()).replaceAll(""));
            }
            for(Constructor ctor : ctors) {
                System.out.println(p.matcher(ctor.toString()).replaceAll(""));
            }
        } catch(ClassNotFoundException e) {}
    }
}
/*
命令 java ShowMethods ShowMethods
public static void main(String[])
public final native void wait(long) throws InterruptedException
public final void wait(long,int) throws InterruptedException
public final void wait() throws InterruptedException
public boolean equals(Object)
public String toString()
public native int hashCode()
public final native Class getClass()
public final native void notify()
public final native void notifyAll()
public ShowMethods()
 */

14.7 动态代理

  • 普通代理
interface Interface {
    void doSomething();
    void somethingElse(String args);
}
class RealObject implements Interface {
    public void doSomething() {
        System.out.println("doSomething");
    }
    public void somethingElse(String args) {
        System.out.println("somethingElse " + args);
    }
}
class SimpleProxy implements Interface {
    //想要将额外的操作从"实际"对象中分离出去
    private Interface proxied;
    public SimpleProxy(Interface proxied) {
        this.proxied = proxied;
    }
    public void doSomething() {
        System.out.println("SimpleProxy doSomething");
        proxied.doSomething();
    }
    public void somethingElse(String args) {
        System.out.println("SimpleProxy somethingElse " + args);
        proxied.somethingElse(args);
    }
}
public class ProxyDemo {
    public static void consumer(Interface iface) {
        iface.doSomething();
        iface.somethingElse("bonobo");
    }
    public static void main(String[] args) {
        consumer(new RealObject());
        consumer(new SimpleProxy(new RealObject()));
    }
}
/*
doSomething
somethingElse bonobo
SimpleProxy doSomething
doSomething
SimpleProxy somethingElse bonobo
somethingElse bonobo
 */
  • 动态代理
import java.lang.reflect.*;
//动态代理处理器,实现调用处理器接口
class MethodSelector implements InvocationHandler {
    private Object proxied;
    public MethodSelector(Object proxied) {
        this.proxied = proxied;
    }
    public Object
    invoke(Object proxy,Method method,Object[] args) throws Throwable
    {
        //过滤某些方法
        if(method.getName().equals("interesting"))
            System.out.println("proxy detected the interesting method");
        return method.invoke(proxied, args);
    }
}
interface SomeMethods {
    void boring1();
    void boring2();
    void interesting(String arg);
    void boring3();
}
class Implementation implements SomeMethods {
    public void boring1() {
        System.out.println("boring1");
    }
    public void boring2() {
        System.out.println("boring2");
    }
    public void interesting(String arg) {
        System.out.println("interesting " + arg);
    }
    public void boring3() {
        System.out.println("boring3");
    }
}
public class SimpleDynamicProxy {
    public static void main(String[] args) {
    //Proxy.newProxyInstance()
    //需要一个类加载器
    //一个接口列表
    //一个InvocationHandler接口的实现
        SomeMethods proxy = (SomeMethods)Proxy.newProxyInstance(
                SomeMethods.class.getClassLoader(),
                new Class[] { SomeMethods.class },
                new MethodSelector(new Implementation())
        );
        proxy.boring1();
        proxy.boring2();
        proxy.interesting("banana");
        proxy.boring3();
    }
}
/*
boring1
boring2
proxy detected the interesting method
interesting banana
boring3
 */


### 14.8 空对象

```java
interface Null {}
public class Person {
    public final String first;
    public final String last;
    public final String address;
    public Person(String first,String last,String address) {
        this.first = first;
        this.last  = last;
        this.address = address;
    }
    public String toString() {
        return "Person: " + first + " " + last + " " + address;
    }
    public static class NullPerson extends Person implements Null {
        private NullPerson() { super("None","None","None") }
        public String toString() { return "NullPerson"; }
    }
    //空对象是单例的
    public static final Person NULL = new NullPerson();
}

if(position.getPerson() == Person.NULL)
;
import javax.management.openmbean.OpenMBeanAttributeInfo;
import java.lang.reflect.*;
import java.util.*;

interface Operation {
    String description();
    void command();
}
//机器人接口
interface Robot {
    String name();
    String model();
    //机器人操作集
    List<Operation> operations();
    class Test {
        //输出操作,包括空操作
        public static void test(Robot r) {
            if (r instanceof Null)
            System.out.println("[Null Robot]");
            System.out.println("Robot name: " + r.name());
            System.out.println("Robot model: " + r.model());
            for(Operation operation : r.operations()) {
                System.out.println(operation.description());
                operation.command();
            }
        }
    }
}
//扫雪机器人
class SnowRemovalRobot implements Robot {
    private String name;
    public SnowRemovalRobot(String name) { this.name = name; }
    public String name() { return name; }
    public String model() { return "SnowBot Series 11"; }
    //操作包括扫雪铲冰清理屋顶
    public List<Operation> operations() {
        return Arrays.asList(
                new Operation() {
                    @Override
                    public String description() {
                        return name + "can shovel snow";
                    }

                    @Override
                    public void command() {
                        System.out.println(name + " shoveling snow");
                    }
                },
                new Operation() {
                    @Override
                    public String description() {
                        return name + "can chip ice";
                    }

                    @Override
                    public void command() {
                        System.out.println(name + " chipping ice");
                    }
                },
                new Operation() {
                    @Override
                    public String description() {
                        return name + "can clear the roof";
                    }

                    @Override
                    public void command() {
                        System.out.println(name + " clearing roof");
                    }
                }
        );
    }
}
//NULL机器人动态代理
class NullRobotProxyHandler implements InvocationHandler {
    private String nullName;
    private Robot proxied = new NRobot();
    NullRobotProxyHandler(Class<? extends Robot> type) {
        nullName = type.getSimpleName() + " NullRobot";
    }
    //空机器人类实现
    private class NRobot implements Null,Robot {
        public String name() { return nullName; }
        public String model() { return nullName; }
        public List<Operation> operations() {
            return Collections.emptyList();
        }
    }
    //动态代理调用
    public Object
    invoke(Object proxy,Method method,Object[] args) throws InvocationTargetException, IllegalAccessException {
        return method.invoke(proxied, args);
    }
}
public class NullRobot {
    //创建一个NullRobot
    public static Robot
    newNullRobot(Class<? extends Robot> type) {
        return (Robot)Proxy.newProxyInstance(
                NullRobot.class.getClassLoader(),
                new Class[]{ Null.class, Robot.class },
                new NullRobotProxyHandler(type)
        );
    }
    public static void main(String[] args) {
        Robot[] bots = {
                new SnowRemovalRobot("Snowbee"),
                newNullRobot(SnowRemovalRobot.class)
        };
        for(Robot bot : bots)
            Robot.Test.test(bot);
    }
}
/*
Robot name: Snowbee
Robot model: SnowBot Series 11
Snowbeecan shovel snow
Snowbee shoveling snow
Snowbeecan chip ice
Snowbee chipping ice
Snowbeecan clear the roof
Snowbee clearing roof
[Null Robot]
Robot name: SnowRemovalRobot NullRobot
Robot model: SnowRemovalRobot NullRobot
 */

14.9 接口与类型信息

  • 接口仍有可能将耦合性传递出去
public interface A {
	void f();
}
class B implements A {
	void f() {}
	void g() {}
}
public class InterfaceViolation {
	public static void main(String[] args) {
		A a = new B();
		a.f();
		//a.g(); 出错
		if(a instanceof B) {
			B b = (B)a;
			b.g();
		}
	}
}
  • 使用包访问权限防止这种情况
class C implements A {
	public void f() {}
	public void g() {}
}
public class HiddenC {
	public static A makeA() { return new C(); }
}
javap -private C
//通过反编译解出源代码
HiddenImplementation.callHiddenMethod(a,"g");
//通过反射可以访问任何private的域
  • 一致的错误报告模型使得我们能够通过使用反射编写动态代码,尽力编写能够进行静态类型检查的代码是值得的,但动态代码也许是Java与其他诸如C++这样的语言区分开的重要工具之一
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值