当我们获取到Class对象时,实际上就获取到了一个类的类型,获取方法一共有三类
1.Class cls = String.class; // 获取到String的Class
2.String s = "";
Class cls = s.getClass(); // s是String,因此获取到String的Class
3.Class s = Class.forName("java.lang.String");//传入Class的完整类名获取
获取父类的Class
有了Class
实例,我们还可以获取它的父类的Class
public class Main {
public static void main(String[] args) throws Exception {
Class i = Integer.class;
Class n = i.getSuperclass();
System.out.println(n);
Class o = n.getSuperclass();
System.out.println(o);
System.out.println(o.getSuperclass());
}
}
output:
class java.lang.Number
class java.lang.Object
null
运行上述代码,可以看到,Integer
的父类类型是Number
,Number
的父类是Object
,Object
的父类是null
。除Object
外,其他任何非interface
的Class
都必定存在一个父类类型。
获取interface
由于一个类可能实现一个或多个接口,通过Class
我们就可以查询到实现的接口类型。例如,查询Integer
实现的接口:
public class getInterface {
public static void main(String[] args) throws Exception {
Class s = String.class;
Class[] is = s.getInterfaces();
for (Class i : is) {
System.out.println(i);
}
}
}
output:
interface java.io.Serializable
interface java.lang.Comparable
interface java.lang.CharSequence
特别注意:getInterfaces()
只返回当前类直接实现的接口类型,并不包括其父类实现的接口类型:
public class getInterface {
public static void main(String[] args) throws Exception {
Class s = Integer.class.getSuperclass();
Class[] is = s.getInterfaces();
for (Class i : is) {
System.out.println(i);
}
}
}
output:
interface java.io.Serializable
Integer
的父类是Number
,Number
实现的接口是java.io.Serializable
。
Integer
的父类是Number
,Number
实现的接口是java.io.Serializable
。
此外,对所有interface
的Class
调用getSuperclass()
返回的是null
,获取接口的父接口要用getInterfaces()
:
System.out.println(java.io.DataInputStream.class.getSuperclass()); // java.io.FilterInputStream,因为DataInputStream继承自FilterInputStream
System.out.println(java.io.Closeable.class.getSuperclass()); // null,对接口调用getSuperclass()总是返回null,获取接口的父接口要用getInterfaces()
如果一个类没有实现任何interface
,那么getInterfaces()
返回空数组。
继承关系
当我们判断一个实例是否是某个类型时,正常情况下,使用instanceof
操作符:
Object n = Integer.valueOf(123);
boolean isDouble = n instanceof Double; // false
boolean isInteger = n instanceof Integer; // true
boolean isNumber = n instanceof Number; // true
boolean isSerializable = n instanceof java.io.Serializable; // true
如果是两个Class
实例,要判断一个向上转型是否成立,可以调用isAssignableFrom()
:
// Integer i = ?
Integer.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Integer
// Number n = ?
Number.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Number
// Object o = ?
Object.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Object
// Integer i = ?
Integer.class.isAssignableFrom(Number.class); // false,因为Number不能赋值给Integer
创建interface实例(动态代理)——可以在运行期动态创建某个interface
的实例(了解)
静态代码——所有interface
类型的变量总是通过向上转型并指向某个实例的
定义接口:
public interface Hello {
void morning(String name);
}
编写实现类:
public class HelloWorld implements Hello {
public void morning(String name) {
System.out.println("Good morning, " + name);
}
}
创建实例,转型为接口并调用:
Hello hello = new HelloWorld();
hello.morning("Bob");
还有一种方式是动态代码,我们仍然先定义了接口Hello
,但是我们并不去编写实现类,而是直接通过JDK提供的一个Proxy.newProxyInstance()
创建了一个Hello
接口对象。这种没有实现类但是在运行期动态创建了一个接口对象的方式,我们称为动态代码。JDK提供的动态创建接口对象的方式,就叫动态代理。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method);
if (method.getName().equals("morning")) {
System.out.println("Good morning, " + args[0]);
}
return null;
}
};
Hello hello = (Hello) Proxy.newProxyInstance(
Hello.class.getClassLoader(), // 传入ClassLoader
new Class[] { Hello.class }, // 传入要实现的接口
handler); // 传入处理调用方法的InvocationHandler
hello.morning("Bob");
}
}
interface Hello {
void morning(String name);
}
把上面的动态代理改写为静态实现类大概长这样:
public class HelloDynamicProxy implements Hello {
InvocationHandler handler;
public HelloDynamicProxy(InvocationHandler handler) {
this.handler = handler;
}
public void morning(String name) {
handler.invoke(
this,
Hello.class.getMethod("morning", String.class),
new Object[] { name });
}
}
在运行期动态创建一个interface
实例的方法如下:
- 定义一个
InvocationHandler
实例,它负责实现接口的方法调用; - 通过
Proxy.newProxyInstance()
创建interface
实例,它需要3个参数:
- 使用的
ClassLoader
,通常就是接口类的ClassLoader
; - 需要实现的接口数组,至少需要传入一个接口进去;
- 用来处理接口方法调用的
InvocationHandler
实例。
- 将返回的
Object
强制转型为接口。