Think in java第十一章笔记

本文探讨了Java中接口、抽象类与普通类的使用,重点介绍了运行时类型信息(RTTI)及其在对象造型过程中的应用。通过具体代码示例,展示了如何在运行时获取和控制对象类型信息,以及利用反射机制操作类、方法和构造器。最后,文章阐述了Class类的isInstance方法和获取类信息的方法,如getInterfaces、getSuperclass等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.

import java.util.*;

interface Shape {
	void draw();
}

class Circle implements Shape {
	public void draw() {
		System.out.println("Circle.draw()");
	}
}

class Square implements Shape {
	public void draw() {
		System.out.println("Square.draw()");
	}
}

class Triangle implements Shape {
	public void draw() {
		System.out.println("Triangle.draw()");
	}
}
public class Shapes {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Vector s = new Vector();
		s.addElement(new Circle());
		s.addElement(new Square());
		s.addElement(new Triangle());
		Enumeration e = s.elements();
		while(e.hasMoreElements())
			((Shape)e.nextElement()).draw();
	}

}
基础类可编写成一个接口,一个抽象类或者一个普通类。在上溯造型至Object的过程中,任何特殊的信息都会丢失,其中甚至包括对象时几何形状这一事实。Vector只容纳Object,所以nextElement()会自然地产生一个Object句柄。但我们知道实际它是个Shape句柄,而且希望将Shape消息发给那个对象。所以需要用传统的(Shape)方式造型成一个Shape。这是RTTI最基本的形式,因为在java中,所有造型都会在运行期间得到检查,以确保其正确性。

我们希望自己的代码尽可能少知道一些与对象的具体类型有关的情况,只将注意力放在某一类对象的常规信息上。

2.

类型信息在运行期是如何表示的??要用到一个名为“Class对象”的特殊形式的对象,其中包含了与类有关的信息。事实上,我们要用Class对象创建属于某个类的全部“常规”或“普通”对象。每个类,它们都有一个Class对象,是保存在一个完全同名的.class文件中。在运行期,一旦我们想生成那个类的一个对象,用于执行程序的java虚拟机(JVM)首先会检查那个类的class对象是否已经载入。若尚未载入,jvm就会查找同名的.class文件,并将其载入。所以java程序启动时并 不是完全载入的。

一旦那个类型的Class对象进入内存,就用它创建那一类型的所有对象。

Class对象和其他任何对象都是类似的,所以能够获取和控制它的一个句柄(装载模块就是干这事的)。为获得Class的一个句柄,一个办法是使用forName()。最后返回的是一个Class句柄。

3.

import java.util.*;
import java.io.*;
class Pet {
	
}
class Dog extends Pet {
	
}
class Pug extends Dog {
	
}
class Cat extends Pet {
	
}
class Rodent extends Pet {
	
}
class Gerbil extends Rodent {
	
}
class Hamster extends Rodent {
	
}

class Counter {
	int i;
}

public class PetCount2 {
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Vector pets = new Vector();
		Class[] petTypes = {
			Pet.class,
			Dog.class,
			Pug.class,
			Cat.class,
			Rodent.class,
			Gerbil.class,
			Hamster.class
		};
		
		try {
			for(int i = 0; i < 15; i++) {
				int rnd = 1 + (int)(Math.random()*(petTypes.length-1));
				pets.addElement(petTypes[rnd].newInstance());
			}
				
		}catch(InstantiationException e) {
			e.printStackTrace();
		}catch(IllegalAccessException e) {
			e.printStackTrace();
		}
		
		Hashtable h = new Hashtable();
		for(int i = 0; i < petTypes.length; i++) {
			h.put(petTypes[i].toString(), new Counter());
		}
		
		for(int i = 0; i < pets.size(); i++) {
			Object o = pets.elementAt(i);
			if(o instanceof Pet) 
				((Counter)h.get("class c11.Pet")).i++;
			if(o instanceof Dog)
				((Counter)h.get("class c11.Dog")).i++;
			if(o instanceof Pug)
				((Counter)h.get("class c11.Pug")).i++;
			if(o instanceof Cat)
				((Counter)h.get("class c11.Cat")).i++;
			if(o instanceof Rodent)
				((Counter)h.get("class c11.Rodent")).i++;
			if(o instanceof Gerbil)
				((Counter)h.get("class c11.Gerbil")).i++;
			if(o instanceof Hamster)
				((Counter)h.get("class c11.Hamster")).i++;
		}
		
		for(int i = 0; i < pets.size(); i++)
			System.out.println(pets.elementAt(i).getClass().toString());
		
		Enumeration keys = h.keys();
		while(keys.hasMoreElements()) {
			String nm = (String)keys.nextElement();
			Counter cnt = (Counter)h.get(nm);
			System.out.println(nm.substring(nm.lastIndexOf('.')+1)+" quantity: "+cnt.i);
		}
	}

}

petTypes的创建模块不需要用一个try块包围起来,因为它会在编译期得到检查,不会像Class.forName()那样“掷”出任何违例。


4.

Class类的isInstance方法,可以动态调用instanceof运算符。


5.

interface HasBatteries {
	
}
interface Waterproff {
	
}
interface ShootsThings {
	
}
class Toy {
	Toy() {
		
	}
	Toy(int i) {
		
	}
}
class FancyToy extends Toy implements HasBatteries, Waterproff, ShootsThings {
	FancyToy() {
		super(1);
	}
}
public class ToyTest {
	
	static void printInfo(Class cc) {
		System.out.println("Class name:"+cc.getName()+" is interface? ["+cc.isInterface()+"]");
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Class c = null;
		
		try {
			c = Class.forName("c11.FancyToy");
		}catch(ClassNotFoundException e) {
			e.printStackTrace();
		}
		
		printInfo(c);
		
		Class[] faces = c.getInterfaces();
		for(int i = 0; i < faces.length; i++)
			printInfo(faces[i]);
		
		Class cy = c.getSuperclass();
		Object o = null;
		try {
			o = cy.newInstance();
		}catch(InstantiationException e) {
			
		}catch(IllegalAccessException e) {
			
		}
		
		printInfo(o.getClass());
	}

}

Class.getInterfaces方法会返回Class对象的一个数组,用于表示包含在Class对象内的接口。若有一个Class对象,也可以用getSuperclass()查询该对象的直接基础类是什么,这会返回一个Class句柄,可用它做进一步的查询。这意味着在运行期的时候,完全有机会调查到对象的完整层次结构。cy只是一个Class句柄,编译期间并知道进一步的类型信息。一旦接受了一个实例后,可以得到Object句柄。但那个句柄指向一个Toy对象。除此之外,用newInstance创建的类必须有一个默认构建器。


6.

针对Field,Method和Constructor类,它们都新增了一个库:java.lang.reflect.这些类型的对象都是jvm在运行期创建的。这样便可调用构建器创建新对象,用get()和set()方法读取和修改与Field对象关联的字段,以及用invoke()方法调用与Method对象关联的方法。此外,我们可以调用方法getFields(),getMethods(),getConstructors(),分别返回用于表示字段、方法及构建器的对象信息。RTTI和“反射”之间的唯一区别就是对RTTI来说,编译器会在编译期打开和检查.class文件。但对反射来说,.class文件在编译期是不可用的,而是由运行期环境检查。


7.

import java.lang.reflect.*;
public class ShowMethods {

	static final String usage = "usage:\n"+
								"ShowMethods qualified.class.name\n"+
								"To show..";
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		if(args.length < 1) {
			System.out.println(usage);
			System.exit(0);
		}
		
		try {
			Class c = Class.forName(args[0]);
			Method[] m = c.getMethods();
			m = c.getDeclaredMethods();
			Constructor[] ctor = c.getConstructors();
			ctor = c.getDeclaredConstructors();
			Field[] fd = c.getFields(); //获取某个类的所有的public字段,包括父类
			fd = c.getDeclaredFields(); //获得某个类的所有声明的字段,即包括public,private和protected,但不包括父类的声明字段。同样的还有getConstructors()和getDeclaredConstructors()
			
			if(args.length == 1) {
				System.out.println(m.length);
				for(int i = 0; i < m.length; i++)
					System.out.println(m[i].toString());
				System.out.println(ctor.length);
				for(int i = 0; i < ctor.length; i++)
					System.out.println(ctor[i].toString());
				System.out.println(fd.length);
				for(int i = 0; i < fd.length; i++)
					System.out.println(fd[i].toString());
			} else {
				for(int i = 0; i < m.length; i++)
					if(m[i].toString().indexOf(args[1]) != -1)
						System.out.println(m[i].toString());
				
				for(int i = 0; i < ctor.length; i++)
					if(ctor[i].toString().indexOf(args[1]) != -1)
						System.out.println(ctor[i].toString());
			}
		}catch(ClassNotFoundException e) {
			System.out.println("No such class: "+e);
		}
	}

}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值