反射 Reflect Class 基础 API MD 目录 反射 Reflection 面试题 附加 类 java.lang.Package 包 public class java.lang.Package extends Object implements AnnotatedElement //注意不是reflect包下的,而直接是lang包下的 演示代码中用到的Bean package com.bqt; ​ import java.io.Serializable; ​ public class Animal implements Serializable { private static final long serialVersionUID = 1L; public int sex; private boolean canFly; ​ public Animal() { } ​

Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

反射 Reflection

面试题

什么是反射

  • 反射机制就是在【运行】状态中,对于任意一个【类】,都能够知道这个类的所有属性和方法;对于任意一个【对象】,都能够调用这个对象的所有属性和方法;这种【动态获取类中的信息】以及【动态调用对象的成员】的功能称为java语言的反射机制。
  • 但是它也有它的缺点,就是运用它会使我们的软件的性能降低,复杂度增加,所以还要我们慎重的使用它。

使用反射有何优缺点
任何事物都有两面性,反射的优点也同是就是它的缺点,所以,没有好与坏,只有最合适的场景。

优点:

  • 反射被广泛地用于那些需要在运行时检测或修改程序行为的程序中,大大提高了程序的灵活性和扩展性。它允许程序创建和控制任何类的对象,无需提前硬编码目标类。
  • 运行期类型的判断,动态类加载,动态代理

缺点:

  • 性能问题:使用反射的性能较低。使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和扩展性要求很高的系统框架上,普通程序不建议使用。
  • 结构问题:使用反射会模糊程序内内部逻辑,破坏了类的封装性。程序员希望在源代码中看到程序的逻辑,反射绕过了源代码的技术,因而会带来维护问题。
  • 安全问题:使用反射技术要求程序必须在一个没有安全限制的环境中运行,如果一个程序必须在有安全限制的环境中运行,那么这就是个问题了。
  • 复杂度问题:反射代码比相应的直接代码更复杂,更难维护。

JAVA是不是动态语言

  • 程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。
  • 从这个观点看,Perl,Python,Ruby,PHP,OCJS等是动态语言,而C,C++,JavaC#不是动态语言。
  • 但是JAVA有着一个非常突出的动态相关机制:反射,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的Class,获悉其完整构造(注意:包括methods声明,但不包括methods定义),并生成其对象实体、或对其Fields设值、或唤起其Methods。

通过反射机制能实现哪些功能

  • 在运行时构造任意一个类的对象,调用任意一个对象的方法,判断任意一个对象所属的类,判断任意一个类所具有的成员变量和方法
  • 生成动态代理

反射机制在哪些框架中有体现

  • 与注解相结合的框架,例如Retrofit(动态代理)
  • 单纯的反射机制应用框架,例如EventBus
  • 动态生成类框架,例如Gson
  • 逆向代码,例如反编译

早期,new一个对象的时候,需先根据被new的类的名称找寻该类的字节码文件,然后加载进内存,并自动创建该字节码文件对象,接着创建该字节文件对应的该类的对象
现在,可以先根据被new的类的名称找寻该名称的类文件,然后加载进内存,最后通过Class对象的newInstance方法产生该类的对象。

PS:字节码文件即.class文件,是经过编译器预处理过的一种文件,是JAVA的执行文件存在形式。它本身是二进制文件,但是不可以被系统直接执行,而是需要虚拟机解释执行,由于被预处理过,所以比一般的解释代码要快,但是仍然会比系统直接执行的慢。

Class 类

public final class java.lang.Class<T> extends Object implements Serializable, GenericDeclaration, Type, AnnotatedElement

类型参数 T:由此 Class 对象建模的类的类型。例如,String.class 的类型是Class<String>。如果将被建模的类未知,则使用 Class<?>

Instances of the class Class represent classes and interfaces in a running Java application. An enum is a kind of class and an annotation is a kind of interface. Every array also belongs to a class that is reflected as a Class object that is shared by all arrays with the same element type and number of dimensions. The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects.

Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是类的一种,注解是接口的一种。每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。八种基本类型和关键字 void 也表示为 Class 对象。

Class has no public constructor. Instead Class objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the defineClass method in the class loader.

Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。

获取对象运行时Class类

final native Class<?> getClass()

  • 返回此 Object 的运行时类。
  • 这是 Object类 中定义的 final、native 方法,返回的 Class 对象是由所表示类的 static synchronized 方法锁定的对象。
  • 实际结果类型是 Class<? extends |X|>,其中 |X| 表示清除表达式中的静态类型,该表达式调用 getClass。例如,以下代码片段中不需要强制转换:
Number n = 0;
Class<? extends Number> c = n.getClass();
System.out.println(c.getName()); //java.lang.Integer

static Class<?> forName(String className)
static Class<?> forName(String name, boolean initialize, ClassLoader loader)

  • 返回与带有给定字符串名的类或接口相关联的 Class 对象。
  • 参数:className - 所需类的完全限定名,以 getName 所返回的格式,如java.lang.Thread
  • 调用此方法等效于:Class.forName(className, true, currentLoader)。其中 currentLoader 表示当前类的定义类加载器。
  • 调用 forName("X") 将导致命名为 X 的类被初始化。
Class<? extends Person> clazz = new Person().getClass();//获取此 Object 的运行时类
Class<Person> clazz2 = Person.class;//任何数据类型的静态的【.class】字段表示其对应的Class对象
Class<?> clazz3 = Class.forName("com.bqt.Person");//只要通过给定的类的字符串名称即可
System.out.println((clazz == clazz2) + "  " + (clazz == clazz3));//true  true

获取与此class对象相关的Class类

<U> Class<? extends U> asSubclass(Class<U> clazz)

  • 强制转换该 Class 对象,以表示指定的 class 对象所表示的类的一个子类。
  • 返回:此 Class 对象,它被强制转换以表示指定类对象的子类。
  • 如果该 Class 对象不表示指定类的子类(这里“子类”包括该类本身),则抛出ClassCastException。
Number n = 0;
Class<? extends Number> c = n.getClass();
Class<? extends Integer> c2 = c.asSubclass(Integer.class);

System.out.println(c.getName() + "   " + c2.getName()); //java.lang.Integer   java.lang.Integer

Class<? super T> getSuperclass()

  • 返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。
  • 如果此 Class 表示 Object 类、一个接口、一个基本类型或 void,则返回 null。
  • 如果此对象表示一个数组类,则返回表示该 Object 类的 Class 对象
Class<? super Integer> c = Integer.class.getSuperclass();
System.out.println(c.getName());//【注意结果】java.lang.Number

Class<?> getComponentType()
如果此类是数组,则返回表示此类组件类型的 Class;如果此类不表示数组类,则此方法返回 null。

Class<?> getDeclaringClass()

  • 如果此 Class 对象所表示的类或接口是另一个类的成员,则返回的 Class 对象表示该对象的声明类。
  • 如果该类或接口不是其他类的成员,则此方法返回 null。
  • 如果此 Class 对象表示一个数组类、基本类型或 void,则此方法返回 null。

Class<?> getEnclosingClass()
返回底层类的立即封闭类。如果底层类是顶层类,则此方法返回 null。

System.out.println(Animal.IEat.class.getComponentType());//null
System.out.println(Animal.IEat.class.getDeclaringClass());//class com.bqt.Animal
System.out.println(Animal.IEat.class.getEnclosingClass());//class com.bqt.Animal

Class<?>[] getClasses()

  • 返回一个包含某些 Class 对象的数组,这些对象表示属于此 Class 对象所表示的类的成员的所有公共类和接口。【我觉得就是指在当前类及超类中定义的 public 的内部类或接口】
  • 包括从超类继承的公共类和接口成员以及该类声明的公共类和接口成员。
  • 如果此 Class 对象没有公共成员类或接口,则此方法返回一个长度为 0 的数组。
  • 如果此 Class 对象表示一个基本类型、一个数组类或 void,则此方法也返回一个长度为 0 的数组。

Class<?>[] getDeclaredClasses()

  • 返回 Class 对象的一个数组,这些对象反映声明为此 Class 对象所表示的类的成员的所有类和接口。【我觉得就是指在当前类中定义的所有内部类或接口】
  • 包括该类所声明的公共、保护、默认(包)访问及私有类和接口,但不包括继承的类和接口。
  • 如果该类不将任何类或接口声明为成员,或者此 Class 对象表示基本类型、数组类或 void,则此方法返回一个长度为 0 的数组。

Class<?>[] getInterfaces()

  • 返回该类所实现的接口的一个数组。
  • 如果此对象表示一个类,则返回值是一个数组,它包含了表示该类所实现的所有接口的对象。数组中接口对象顺序与此对象所表示的类的声明的 implements 子句中接口名顺序一致。
  • 如果此对象表示一个接口,则该数组包含表示该接口扩展的所有接口的对象。数组中接口对象顺序与此对象所表示的接口的声明的 extends 子句中接口名顺序一致。
  • 如果此对象表示一个不实现任何接口的类或接口,则此方法返回一个长度为 0 的数组。
  • 如果此对象表示一个基本类型或 void,则此方法返回一个长度为 0 的数组。
Class<Person> c = Person.class;
System.out.println(Arrays.toString(c.getClasses()));//[interface com.bqt.Person$IRun, interface com.bqt.Animal$IEat]
System.out.println(Arrays.toString(c.getDeclaredClasses()));//[class com.bqt.Person$Car, interface com.bqt.Person$IRun]
System.out.println(Arrays.toString(c.getInterfaces()));//[interface java.lang.Cloneable, interface java.io.Serializable]

返回 Type (接口与超类)

Type[] getGenericInterfaces()

  • 返回表示某些接口的 Type 数组,这些接口由此对象所表示的类或接口直接实现。【返回此类所实现的接口的Type数组】
  • 如果超接口是ParameterizedType(参数化类型),则为它返回的 Type 对象必须准确反映源代码中所使用的实际类型参数。如果以前未曾创建表示每个超接口的参数化类型,则创建这个类型。有关参数化类型创建过程的语义,请参阅 ParameterizedType 声明。
  • 如果此对象表示一个类,则返回一个包含这样一些对象的数组,这些对象表示该类实现的所有接口。数组中接口对象顺序与此对象所表示的类的声明的 implements 子句中接口名顺序一致。对于数组类,接口 Cloneable 和 Serializable 以该顺序返回。
  • 如果此对象表示一个接口,则该数组包含表示该接口直接扩展的所有接口的对象。数组中接口对象顺序与此对象所表示的接口的声明的 extends 子句中接口名顺序一致。
  • 如果此对象表示一个不实现任何接口的类或接口,则此方法返回一个长度为 0 的数组。
  • 如果此对象表示一个基本类型或 void,则此方法返回一个长度为 0 的数组。

Type getGenericSuperclass()

  • 返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的直接超类的 Type。
  • 如果超类是ParameterizedType(参数化类型),则返回的 Type 对象必须准确反映源代码中所使用的实际类型参数。如果以前未曾创建表示超类的参数化类型,则创建这个类型。有关参数化类型创建过程的语义,请参阅 ParameterizedType 声明。
  • 如果此 Class 表示 Object 类、接口、基本类型或 void,则返回 null。
  • 如果此对象表示一个数组类,则返回表示 Object 类的 Class 对象。
public class Test<T> extends Person implements Cloneable, Comparable<T> {

    public static void main(String[] args) throws NoSuchMethodException, SecurityException {
        Type[] types = Test.class.getGenericInterfaces();
        for (Type type : types) {
            System.out.println(type + " , " + type.getClass().getSimpleName());
            //【interface java.lang.Cloneable , Class】和【java.lang.Comparable<T> , ParameterizedTypeImpl】
        }

        Type type = Test.class.getGenericSuperclass();
        System.out.println(type + " , " + type.getClass().getSimpleName()); //class com.bqt.Person , Class
    }

    @Override
    public int compareTo(T t) {
        return 0;
    }
}

获取构造器 Constructor

Constructor<?>[] getConstructors()

  • 返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法
  • 如果该类没有公共构造方法,或者该类是一个数组类,或者该类反映一个基本类型或 void,则返回一个长度为 0 的数组。
  • 注意,此方法返回 Constructor<T> 对象的数组(即取自此类构造方法的数组)时,此方法的返回类型是 Constructor<?>[],不是预期的 Constructor<T>[]。此少量信息的返回类型是必需的,因为从此方法返回之后,该数组可能被修改以保存不同类的 Constructor 对象,而这将违反 Constructor<T>[] 的类型保证。

Constructor<?>[] getDeclaredConstructors()

  • 返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法,包括是公共、保护、默认(包)访问和私有构造方法。
  • 返回数组中的元素没有排序,也没有任何特定的顺序。
  • 如果该类存在一个默认构造方法,则它包含在返回的数组中。
  • 如果此 Class 对象表示一个接口、一个基本类型、一个数组类或 void,则此方法返回一个长度为 0 的数组。
System.out.println(Arrays.toString(Person.class.getConstructors()));
//[public com.bqt.Person(), public com.bqt.Person(java.lang.String,int)]

System.out.println(Arrays.toString(Person.class.getDeclaredConstructors()));
//[private com.bqt.Person(int), public com.bqt.Person(), public com.bqt.Person(java.lang.String,int)]

T newInstance()

  • 创建此 Class 对象所表示的类的一个新分配的实例。
  • 如同用一个带有一个空参数列表的 new 表达式实例化该类。如果该类尚未初始化,则初始化这个类。

Constructor<T> getConstructor(Class<?>... parameterTypes)

  • 返回一个与指定的 parameterTypes 相匹配的公共构造方法的 Constructor 对象
  • parameterTypes 参数是 Class 对象的一个数组,这些 Class 对象按声明顺序标识构造方法的形参类型。如果此 Class 对象表示非静态上下文中声明的内部类,则形参类型作为第一个参数包括显示封闭的实例。
  • 要反映的构造方法是此 Class 对象所表示的类的公共构造方法,其形参类型与 parameterTypes 所指定的参数类型相匹配。

Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

  • 返回一个 Class 对象的数组,表示该类的所有 declared 成员,包括该类所声明的公共、保护、默认(包)访问及私有类和接口,但不包括继承的类和接口。
  • 如果该类不将任何类或接口声明为成员,或者此 Class 对象表示基本类型、数组类或 void,则此方法返回一个长度为 0 的数组。

Constructor<?> getEnclosingConstructor()

  • 如果该 Class 对象表示构造方法中的一个本地或匿名类,则返回 Constructor 对象,它表示底层类的立即封闭构造方法。否则返回 null。
  • 返回:如果该类是本地或匿名类,则返回底层类的立即封闭构造方法;否则返回 null。
  • 特别地,如果底层类是由一个类型声明、实例初始值设定项或静态初始值设定项立即封闭的本地或匿名类,则此方法返回 null。
Class<Person> c = Person.class;
System.out.println(c.newInstance().age);//必须有【公共的、无参构造方法】
Constructor<Person> cs = c.getConstructor(String.class, int.class); //公共构造方法
System.out.println(cs.newInstance("包青天", 28).age);

Constructor<Person> cs2 = c.getDeclaredConstructor(int.class);//包含私有构造方法
cs2.setAccessible(true);//必须设置!Class Test can not access a member of class com.bqt.Person with modifiers "private"
System.out.println(cs2.newInstance(10086).age);

获取方法 Method

Method[] getDeclaredMethods()
返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。

Method[] getMethods()
返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。

Method getMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。

参数:name - 方法名;parameterTypes - 参数列表。

  • name 参数是一个 String,用于指定所需方法的简称。
  • parameterTypes 参数是按声明顺序标识该方法形参类型的 Class 对象的一个数组。如果 parameterTypes 为 null,则按空数组处理。

返回:与指定的 name 和 parameterTypes 匹配的 Method 对象

如果 name 是 <init><clinit>,则将引发 NoSuchMethodException。否则,要反映的方法由下面的算法确定(设 C 为此对象所表示的类):

  • 在 C 中搜索任一匹配的方法。如果找不到匹配的方法,则将在 C 的超类上递归调用第 1 步算法。
  • 如果在第 1 步中没有找到任何方法,则在 C 的超接口中搜索匹配的方法。如果找到了这样的方法,则反映该方法。

在 C 类中查找匹配的方法:如果 C 正好声明了一个具有指定名称的公共方法并且恰恰有相同的形参类型,则它就是反映的方法。如果在 C 中找到了多个这样的方法,并且其中有一个方法的返回类型比其他方法的返回类型都特殊,则反映该方法;否则将从中任选一个方法。

注意,类中可以有多个匹配方法,因为尽管 Java 语言禁止类声明带有相同签名但不同返回类型的多个方法,但 Java 虚拟机并不禁止。这增加了虚拟机的灵活性,可以用来实现各种语言特性。例如,可以使用桥方法 (brige method)实现协变返回;桥方法以及将被重写的方法将具有相同的签名,不同的返回类型。

Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。

Method getEnclosingMethod()

  • 如果此 Class 对象表示某一方法中的一个本地或匿名类,则返回 Method 对象,它表示底层类的立即封闭方法。否则返回 null。
  • 返回:如果该类是本地或匿名类,则返回底层类的立即封闭方法;否则返回 null。
  • 特别地,如果底层类是由一个类型声明、实例初始值设定项或静态初始值设定项立即封闭的本地或匿名类,则此方法返回 null。
Method method = Person.class.getMethod("speak", String.class);
method.invoke(new Person(), "包青天");//sex:0  canFly:false         包青天

method = Person.class.getDeclaredMethod("privateMethod");
method.setAccessible(true);
method.invoke(new Person("包青天", 28));//私有方法:包青天
public class Test {

    public static void main(String[] args) throws Exception {
        A a = new A();
        Method method = a.getClass().getMethod("test", String.class, int.class);//不能用【Integer.class】来代替
        method.invoke(a, "参数", 10086);

        method = a.getClass().getDeclaredMethod("test", String.class, Integer.class); //必须使用getDeclaredMethod
        method.setAccessible(true); //必须设置
        method.invoke(a, "参数", 10087);
    }
}

class A {
    public void test(String s, int i) {
        System.out.println(s + ", int=" + i);
    }

    private void test(String s, Integer i) {
        System.out.println(s + ", Integer=" + i);
    }
}

获取字段 Field

  • Field[] getDeclaredFields():返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所【声明】的所有字段。
  • Field[] getFields():返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有【可访问】公共字段。
  • Field getDeclaredField(String name):返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定【已声明】字段。
  • Field getField(String name):返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定【公共成员】字段。
Class<Person> c = Person.class;
System.out.println(Arrays.toString(c.getFields()));//[public int com.bqt.Person.age, public int com.bqt.Animal.sex]
System.out.println(Arrays.toString(c.getDeclaredFields()));//[private static final long com.bqt.Person.serialVersionUID, public int com.bqt.Person.age, private java.lang.String com.bqt.Person.name]

Field field = c.getField("sex");//公有的字段,包含父类的字段,不包括私有字段
Field field2 = c.getDeclaredField("name");// 已声明的字段,包含私有字段,不包括父类中声明的字段
System.out.println(field + " ★ " + field2);//public int com.bqt.Animal.sex ★ private java.lang.String com.bqt.Person.name

获取注解 Annotation

Class 类中获取注解的四个方法,全部是接口 AnnotatedElement 中的方法,具体用法详见本笔记下方的 AnnotatedElement 接口一节。

<A extends Annotation> A  getAnnotation(Class<A> annotationClass)
Annotation[]  getAnnotations()
Annotation[]  getDeclaredAnnotations()
boolean  isAnnotationPresent(Class<? extends Annotation> annotationClass)

名称 String

  • String getName() 以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
  • String getTypeName() 接口Type中的方法,@since 1.8,The default implementation calls toString().
  • String getSimpleName() 返回源代码中给出的底层类的简称。如果底层类是匿名的则返回一个空字符串。数组的简称即附带 "[]" 的组件类型的简称。特别地,组件类型为匿名的数组的简称是 "[]"。
  • String getCanonicalName() 返回 Java Language Specification 中所定义的底层类的规范化名称。如果底层类没有规范化名称(即如果底层类是一个组件类型没有规范化名称的本地类、匿名类或数组),则返回 null。
  • String toString() 将对象转换为字符串。字符串的表示形式为字符串 "class" 或 "interface" 后面紧跟一个空格,然后是该类的完全限定名,它具有 getName 返回的那种格式。如果此 Class 对象表示一个基本类型,则此方法返回该基本类型的名称。如果该 Class 对象表示 void,则此方法返回 "void"。
System.out.println(String.class.getSimpleName() + ", " + String.class.getCanonicalName());//String, java.lang.String
System.out.println(String.class.getName() + ", " + String.class.getTypeName());//java.lang.String, java.lang.String
System.out.println(String.class);//class java.lang.String

System.out.println(Type.class.getSimpleName() + ", " + Type.class.getCanonicalName());//Type, java.lang.reflect.Type
System.out.println(Type.class.getName() + ", " + Type.class.getTypeName());//java.lang.reflect.Type, java.lang.reflect.Type
System.out.println(Type.class);//interface java.lang.reflect.Type

方返回 boolean 的方法

  • boolean desiredAssertionStatus() 如果要在调用此方法时将要初始化该类,则返回将分配给该类的断言状态。
  • boolean isAnnotation() 如果此 Class 对象表示一个注解类型则返回 true。
  • boolean isAnonymousClass() 当且仅当底层类是匿名类时返回 true。
  • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 接口 AnnotatedElement 中的方法,如果指定注解类型的注解存在于此对象上,则返回 true,否则返回 false
  • boolean isArray() 判定此 Class 对象是否表示一个数组类。
  • boolean isAssignableFrom(Class<?> cls) 判定此 Class 对象所表示的类或接口与指定的 Class 参数所表示的类或接口是否相同,或是否是其超类或超接口。
  • boolean isEnum() 当且仅当该类声明为源代码中的枚举时返回 true。
  • boolean isInstance(Object obj) 判定指定的 Object 是否与此 Class 所表示的对象赋值兼容。
  • boolean isInterface() 判定指定的 Class 对象是否表示一个接口类型。
  • boolean isLocalClass() 当且仅当底层类是本地类时返回 true。
  • boolean isMemberClass() 当且仅当底层类是成员类时返回 true。
  • boolean isPrimitive() 判定指定的 Class 对象是否表示一个基本类型。
  • boolean isSynthetic() 如果此类是复合类,则返回 true,否则 false。

其他方法

  • TypeVariable<Class<T>>[] getTypeParameters() 接口 GenericDeclaration 中的方法
  • int getModifiers() 返回此类或接口以整数编码的 Java 语言修饰符。它们应当使用 Modifier 类的方法来解码。Java Virtual Machine Specification 中的表 4.1 对修饰符编码进行了详细说明。
  • T cast(Object obj) 将一个对象强制转换成此 Class 对象所表示的类或接口。
  • ClassLoader getClassLoader() 返回该类的类加载器。
  • T[] getEnumConstants() 如果此 Class 对象不表示枚举类型,则返回枚举类的元素或 null。
  • ProtectionDomain getProtectionDomain() 返回该类的 ProtectionDomain。
  • URL getResource(String name) 查找带有给定名称的资源。
  • InputStream getResourceAsStream(String name) 查找具有给定名称的资源。
  • Object[] getSigners() 获取此类的标记。
  • Package getPackage() 获取此类的包。

Field 类

public final class java.lang.reflect.Field extends  AccessibleObject  implements  Member

A Field provides information about, and dynamic access to, a single field of a class or an interface. The reflected field may be a class (static) field or an instance field.

Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。

A Field permits widening conversions to occur during a get or set access operation, but throws an IllegalArgumentException if a narrowing conversion would occur.

Array 允许在执行 get 或 set 访问操作期间进行扩展转换,但如果将发生收缩转换,则抛出一个 IllegalArgumentException。

基本数据类型

get 方法

  • boolean getBoolean(Object obj) 获取一个静态或实例 boolean 字段的值。
  • byte getByte(Object obj) 获取一个静态或实例 byte 字段的值。
  • char getChar(Object obj) 获取 char 类型或另一个通过扩展转换可以转换为 char 类型的基本类型的静态或实例字段的值。
  • double getDouble(Object obj) 获取 double 类型或另一个通过扩展转换可以转换为 double 类型的基本类型的静态或实例字段的值。
  • float getFloat(Object obj) 获取 float 类型或另一个通过扩展转换可以转换为 float 类型的基本类型的静态或实例字段的值。
  • int getInt(Object obj) 获取 int 类型或另一个通过扩展转换可以转换为 int 类型的基本类型的静态或实例字段的值。
  • long getLong(Object obj) 获取 long 类型或另一个通过扩展转换可以转换为 long 类型的基本类型的静态或实例字段的值。
  • short getShort(Object obj) 获取 short 类型或另一个通过扩展转换可以转换为 short 类型的基本类型的静态或实例字段的值。

set 方法

  • void setBoolean(Object obj, boolean z) 将字段的值设置为指定对象上的一个 boolean 值。
    • 该方法等同于 set(obj, zObj),其中 zObj 是一个 Boolean 对象,并且 zObj.booleanValue() == z。
    • 参数:obj - 应该修改其字段的对象;b - 正被修改的 obj 的字段的新值
  • void setByte(Object obj, byte b) 将字段的值设置为指定对象上的一个 byte 值。
  • void setChar(Object obj, char c) 将字段的值设置为指定对象上的一个 char 值。
  • void setDouble(Object obj, double d) 将字段的值设置为指定对象上的一个 double 值。
  • void setFloat(Object obj, float f) 将字段的值设置为指定对象上的一个 float 值。
  • void setInt(Object obj, int i) 将字段的值设置为指定对象上的一个 int 值。
  • void setLong(Object obj, long l) 将字段的值设置为指定对象上的一个 long 值。
  • void setShort(Object obj, short s) 将字段的值设置为指定对象上的一个 short 值。

get/set 方法

get 方法

Object get(Object obj)  //返回指定对象上此 Field 表示的字段的值。

参数:obj - 从中提取所表示字段的值的对象
返回:对象 obj 中的所表示字段的值;在返回之前,基值包装在一个适当的对象中

底层字段的值是按以下方式获得的:

  • 如果底层字段是一个静态字段,则忽略 obj 变量;它可能为 null。
  • 否则,底层字段是一个实例字段。如果指定的 obj 变量为 null,则该方法将抛出一个 NullPointerException。如果指定对象不是声明底层字段的类或接口的实例,则该方法将抛出一个 IllegalArgumentException。
  • 如果此 Field 对象强制实施 Java 语言访问控制,并且底层字段是不可访问的,则该方法将抛出一个 IllegalAccessException。
  • 如果底层字段是静态的,并且声明该字段的类尚未初始化,则初始化这个类。
  • 否则,从底层实例字段或静态字段中获取该值。如果该字段是一个基本类型字段,则在返回前将该值包装在一个对象中,否则照原样返回。
  • 如果字段隐藏在 obj 的类型中,则根据前面的规则获得字段的值。

set 方法

void  set(Object obj, Object value)  //将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

进行此操作的方式如下:

  • 如果底层字段是静态字段,则忽略 obj 变量;它可能为 null。
  • 否则底层字段是一个实例字段。如果指定对象变量为 null,则该方法将抛出一个 NullPointerException。如果指定对象变量不是声明底层字段的类或接口的实例,则该方法将抛出一个 IllegalArgumentException。
  • 如果此 Field 对象实施 Java 语言访问控制,并且底层字段是不可访问的,则该方法将抛出一个 IllegalAccessException。
  • 如果底层字段为 final 字段,则该方法将抛出一个 IllegalAccessException,除非 setAccessible(true) 已经继承该字段并且该字段是一个非静态字段。在通过程序的其他部分可以访问类的实例之前,只有使用空白 final 字段反序列化或重构类的实例期间,以这种方式设置 final 字段才有意义。在其他任何上下文中使用该方法都可能会有不可预知的结果,包括程序的其他部分继续使用该字段的原始值的情况。
  • 如果底层字段的类型为某一基本类型,则可以尝试使用解包转换将新值转换为基本类型的值。如果该尝试失败,则此方法将抛出一个 IllegalArgumentException。
  • 如果在进行可能的解包之后,无法通过某一标识或扩展转换将新值转换为底层字段的类型,则此方法将抛出一个 IllegalArgumentException。
  • 如果底层字段是静态的,并且声明该字段的类尚未初始化,则初始化这个类。
  • 字段被设置为可能已解包并扩大的新值。
  • 如果字段隐藏在 obj 的类型中,则根据前面的规则设置字段的值。

其他方法

  • <T extends Annotation> T getAnnotation(Class<T> annotationClass) 如果存在该元素的指定类型的注解,则返回这些注解,否则返回 null。
  • Annotation[] getDeclaredAnnotations() 返回直接存在于此元素上的所有注解。
  • Class<?> getDeclaringClass() 返回表示类或接口的 Class 对象,该类或接口声明由此 Field 对象表示的字段。
  • Class<?> getType() 返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。
  • String getName() 返回此 Field 对象表示的字段的名称。
  • String toGenericString() 返回一个描述此 Field(包括其一般类型)的字符串。
  • String toString() 返回一个描述此 Field 的字符串。
  • boolean isEnumConstant() 如果此字段表示枚举类型的元素,则返回 true;否则返回 false。
  • boolean isSynthetic() 如果此字段是复合字段,则返回 true;否则返回 false。
  • boolean equals(Object obj) 将此 Field 与指定对象比较。
  • Type getGenericType() 返回一个 Type 对象,它表示此 Field 对象所表示字段的声明类型。
  • int getModifiers() 以整数形式返回由此 Field 对象表示的字段的 Java 语言修饰符。它们应当使用 Modifier 类的方法来解码。
  • int hashCode() 返回该 Field 的哈希码。

Method 类

public final class java.lang.reflect.Method extends AccessibleObject implements GenericDeclaration, Member

A Method provides information about, and access to, a single method on a class or interface. The reflected method may be a class method or an instance method (including an abstract method).

Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。

A Method permits widening conversions to occur when matching the actual parameters to invoke with the underlying method's formal parameters, but it throws an IllegalArgumentException if a narrowing conversion would occur.

Method 允许在匹配要调用的实参与底层方法的形参时进行扩展转换;但如果要进行收缩转换,则会抛出 IllegalArgumentException。

invoke 方法

Object  invoke(Object obj, Object... args)

对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。

参数:obj - 从中调用底层方法的对象;args - 用于方法调用的参数
返回:使用参数 args 在 obj 上指派该对象所表示方法的结果

个别参数被自动解包,以便与基本形参相匹配,基本参数和引用参数都随需服从方法调用转换。

  • 如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null。
  • 如果底层方法所需的形参个数为 0,则所提供的 args 数组长度可以为 0 或 null。
  • 如果底层方法是实例方法,则使用动态方法查找来调用它,这一点记录在 Java Language Specification, Second Edition 的第 15.12.4.4 节中;在发生基于目标对象的运行时类型的重写时更应该这样做。
  • 如果底层方法是静态的,并且尚未初始化声明此方法的类,则会将其初始化。
  • 如果方法正常完成,则将该方法返回的值返回给调用者;如果该值为基本类型,则首先适当地将其包装在对象中。但是,如果该值的类型为一组基本类型,则数组元素不被包装在对象中;换句话说,将返回基本类型的数组。如果底层方法返回类型为 void,则该调用返回 null。

其他方法

【Class】

  • Class<?> getDeclaringClass() 返回表示声明由此 Method 对象表示的方法的类或接口的 Class 对象。
  • Class<?>[] getExceptionTypes() 返回 Class 对象的数组,这些对象描述了声明将此 Method 对象表示的底层方法抛出的异常类型。
  • Class<?>[] getParameterTypes() 按照声明顺序返回 Class 对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型。
  • Class<?> getReturnType() 返回一个 Class 对象,该对象描述了此 Method 对象所表示的方法的正式返回类型。

【Type】

  • Type[] getGenericExceptionTypes() 返回 Type 对象数组,这些对象描述了声明由此 Method 对象抛出的异常。
  • Type[] getGenericParameterTypes() 按照声明顺序返回 Type 对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型的。
  • Type getGenericReturnType() 返回表示由此 Method 对象所表示方法的正式返回类型的 Type 对象。

【Annotation】

  • <T extends Annotation> T getAnnotation(Class<T> annotationClass) 如果存在该元素的指定类型的注解,则返回这些注解,否则返回 null。
  • Annotation[] getDeclaredAnnotations() 返回直接存在于此元素上的所有注解。
  • Annotation[][] getParameterAnnotations() 返回表示按照声明顺序对此 Method 对象所表示方法的形参进行注解的那个数组的数组。

【String】

  • String getName() 以 String 形式返回此 Method 对象表示的方法名称。
  • String toGenericString() 返回描述此 Method 的字符串,包括类型参数。
  • String toString() 返回描述此 Method 的字符串。

【boolean】

  • boolean isBridge() 如果此方法是 bridge 方法,则返回 true;否则,返回 false。
  • boolean isSynthetic() 如果此方法为复合方法,则返回 true;否则,返回 false。
  • boolean isVarArgs() 如果将此方法声明为带有可变数量的参数,则返回 true;否则,返回 false。
  • boolean equals(Object obj) 将此 Method 与指定对象进行比较。

【其他】

  • TypeVariable<Class<T>>[] getTypeParameters() 接口 GenericDeclaration 中的方法
  • Object getDefaultValue() 返回由此 Method 实例表示的注解成员的默认值。
  • int getModifiers() 以整数形式返回此 Method 对象所表示方法的 Java 语言修饰符。它们应当使用 Modifier 类的方法来解码。
  • int hashCode() 返回此 Method 的哈希码。

Constructor 类

public final class java.lang.reflect.Constructor<T> extends AccessibleObject implements GenericDeclaration, Member

Constructor provides information about, and access to, a single constructor for a class.

Constructor 提供关于类的单个构造方法的信息以及对它的访问权限。

Constructor permits widening conversions to occur when matching the actual parameters to newInstance() with the underlying constructor's formal parameters, but throws an IllegalArgumentException if a narrowing conversion would occur.

Constructor 允许在将实参与带有底层构造方法的形参的 newInstance() 匹配时进行扩展转换,但是如果发生收缩转换,则抛出 IllegalArgumentException。

newInstance 方法

T  newInstance(Object... initargs)

使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。

参数:initargs - 将作为变量传递给构造方法调用的对象数组;基本类型的值被包装在适当类型的包装器对象中。
返回:通过调用此对象表示的构造方法来创建的新对象

个别参数会自动解包,以匹配基本形参,必要时,基本参数和引用参数都要进行方法调用转换。

  • 如果底层构造方法所需形参个数为 0,则所提供的 initargs 数组的长度可能为 0 或 null。
  • 如果构造方法的声明类是非静态上下文的内部类,则构造方法的第一个参数需要是封闭实例;请参阅Java 语言规范 第 15.9.3 节。
  • 如果所需的访问检查和参数检查获得成功并且实例化继续进行,这时构造方法的声明类尚未初始化,则初始化这个类。
  • 如果构造方法正常完成,则返回新创建且已初始化的实例。

其他方法

【Class】

  • Class<T> getDeclaringClass() 返回 Class 对象,该对象表示声明由此 Constructor 对象表示的构造方法的类。
  • Class<?>[] getExceptionTypes() 返回一组表示声明要抛出的异常类型的 Class 对象,这些异常是由此 Constructor 对象表示的底层构造方法抛出的。
  • Class<?>[] getParameterTypes() 按照声明顺序返回一组 Class 对象,这些对象表示此 Constructor 对象所表示构造方法的形参类型。

【Type】

  • Type[] getGenericExceptionTypes() 返回一组 Type 对象,这些对象表示声明要由此 Constructor 对象抛出的异常。
  • Type[] getGenericParameterTypes() 按照声明顺序返回一组 Type 对象,这些对象表示此 Constructor 对象所表示的方法的形参类型。

【Annotation】

  • <T extends Annotation> T getAnnotation(Class<T> annotationClass) 如果存在该元素的指定类型的注解,则返回这些注解,否则返回 null。
  • Annotation[] getDeclaredAnnotations() 返回直接存在于此元素上的所有注解。
  • Annotation[][] getParameterAnnotations() 按照声明顺序返回一组数组,这些数组表示通过此 Constructor 对象表示的方法的形参上的注解。

【String】

  • String getName() 以字符串形式返回此构造方法的名称。
  • String toGenericString() 返回描述此 Constructor 的字符串,其中包括类型参数。
  • String toString() 返回描述此 Constructor 的字符串。

【boolean】

  • boolean isSynthetic() 如果此构造方法是一个复合构造方法,则返回 true;否则返回 false。
  • boolean isVarArgs() 如果声明此构造方法可以带可变数量的参数,则返回 true;否则返回 false。
  • boolean equals(Object obj) 将此 Constructor 对象与指定的对象进行比较。

【其他】

  • TypeVariable<Class<T>>[] getTypeParameters() 接口 GenericDeclaration 中的方法
  • int getModifiers() 以整数形式返回此 Constructor 对象所表示构造方法的 Java 语言修饰符。它们应当使用 Modifier 类的方法来解码。
  • int hashCode() 返回此 Constructor 的哈希码。

附加

类 java.lang.Package 包

public class java.lang.Package extends Object implements AnnotatedElement  //注意不是reflect包下的,而直接是lang包下的

Package 对象包含有关 Java 包的实现和规范的版本信息。通过用于加载类的 ClassLoader 实例,可以获取并获得此版本信息。通常,此信息存储在与类一起分发的清单中。

【静态方法】

  • static Package getPackage(String name) 通过调用方的 ClassLoader 实例中的名称找到一个包。
  • static Package[] getPackages() 获得调用方的 ClassLoader 实例当前已知的所有包。

【AnnotatedElement接口中的方法】

  • <T extends Annotation> T getAnnotation(Class<T> annotationClass)
  • Annotation[] getAnnotations()
  • Annotation[] getDeclaredAnnotations()
  • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

【String】

  • String getImplementationTitle() 返回此包的标题。
  • String getImplementationVendor() 返回提供该实现的组织、供应商或公司的名称。
  • String getImplementationVersion() 返回该实现的版本。
  • String getName() 返回此包的名称。
  • String getSpecificationTitle() 返回此包实现的规范标题。
  • String getSpecificationVendor() 返回拥有并维护实现此包的类规范的组织、供应商或公司的名称。
  • String getSpecificationVersion() 返回此包实现的规范的版本号。
  • String toString() 返回此 Package 的字符串表示形式。

【boolean】

  • boolean isCompatibleWith(String desired) 比较此包的规范版本和所需版本。
  • boolean isSealed() 如果此包是密封的,则返回 ture。
  • boolean isSealed(URL url) 如果此包对于指定的代码源 url 是密封的,则返回 ture。

【其他】

  • int hashCode() 返回从包名称计算的哈希码。

类 AccessibleObject 访问控制【重要】

public class java.lang.reflect.AccessibleObject extends Object implements AnnotatedElement

直接已知子类:Constructor、Field、Method

AccessibleObject 类是 Field、Method 和 Constructor 对象的基类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。

对于公共成员、默认(打包)访问成员、受保护成员和私有成员,在分别使用 Field、Method 或 Constructor 对象来设置或获取字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查。

在反射对象中设置 accessible 标志允许具有足够特权的复杂应用程序以某种通常禁止使用的方式来操作对象(比如 Java Object Serialization 或其他持久性机制)。

构造方法 protected AccessibleObject() 仅供 Java 虚拟机使用。

以下3个是与访问检查相关的方法

  • boolean isAccessible() 获取此对象的 accessible 标志的值。
  • void setAccessible(boolean flag) 将此对象的 accessible 标志设置为指示的值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查,否则指示反射的对象应该实施 Java 语言访问检查。
  • static void setAccessible(AccessibleObject[] array, boolean flag) 使用单一安全性检查(为了提高效率)为一组对象设置 accessible 标志的便捷方法。参数:array - AccessibleObjects 的数组;flag - 每个对象中的 accessible 标志的新值

以下4个是AnnotatedElement接口中的方法

  • <T extends Annotation> T getAnnotation(Class<T> annotationClass)
  • Annotation[] getAnnotations()
  • Annotation[] getDeclaredAnnotations()
  • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

接口 AnnotatedElement 注解

public interface java.lang.reflect.AnnotatedElement    //注意,他也是reflect包下的,而非annotation包下的

所有已知实现类:Class、Package、AccessibleObject(包括其子类:Constructor、Field、Method)

表示目前正在此 VM 中运行的程序的一个已注解元素。该接口允许反射性地读取注解。由此接口中的方法返回的所有注解都是不可变并且可序列化的。调用者可以修改已赋值数组枚举成员的访问器返回的数组;这不会对其他调用者返回的数组产生任何影响。

  • 如果此接口中的方法返回的注解(直接或间接地)包含一个已赋值的 Class 成员,该成员引用了一个在此 VM 中不可访问的类,则试图通过在返回的注解上调用相关的类返回的方法来读取该类,将导致一个 TypeNotPresentException。
  • 类似地,如果注解中的枚举常量不再以枚举类型存在,那么试图读取一个已赋值的枚举成员将导致一个 EnumConstantNotPresentException。
  • 最后,阅读其定义已经引起不兼容性的成员将导致 AnnotationTypeMismatchException 或 IncompleteAnnotationException。

四个方法
<A extends Annotation> A getAnnotation(Class<A> annotationClass)

  • 如果存在该元素的指定类型的注解,则返回这些注解,否则返回 null。
  • 参数:annotationClass - 对应于注解类型的 Class 对象
  • 返回:如果该元素的指定注解类型的注解存在于此对象上,则返回这些注解,否则返回 null

Annotation[] getAnnotations()

  • 返回此元素上存在的所有注解。
  • 返回:此元素上存在的所有注解,如果此元素没有注解,则返回长度为零的数组。
  • 该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。

Annotation[] getDeclaredAnnotations()

  • 返回直接存在于此元素上的所有注解。
  • 返回:直接存在于此元素上的所有注解,如果没有注解直接存在于此元素上,则返回长度为零的一个数组。
  • 与此接口中的其他方法不同,该方法将忽略继承的注解。
  • 该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。

boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)

  • 如果指定类型的注解存在于此元素上,则返回 true,否则返回 false。
  • 参数:annotationClass - 对应于注解类型的 Class 对象
  • 返回:如果指定注解类型的注解存在于此对象上,则返回 true,否则返回 false
  • 此方法主要是为了便于访问标记注解而设计的。
@SuppressWarnings("unused")//保留策略为【SOURCE】
@UserInfo(age = 28, sex = UserInfo.SexEnum.男, username = "白乾涛", data = "2017.9.2 15:03")//保留策略为【CLASS】
@Citys({ "广州", "深圳", })//保留策略为【RUNTIME】
@Deprecated//保留策略为【RUNTIME】
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
    Method method = Test.class.getMethod("main", String[].class);
    //注意:使用默认保留策略CLASS以及SOURCE的注解,不能通过反射获取注解信息!
    System.out.println(Arrays.toString(method.getAnnotations()));//[@com.bqt.Citys(username=包青天, value=[广州, 深圳]), @java.lang.Deprecated()]
    System.out.println(Arrays.toString(method.getDeclaredAnnotations()));//忽略继承的注解
    System.out.println(method.isAnnotationPresent(Citys.class) + "  " + method.isAnnotationPresent(UserInfo.class));//true  false

    Citys ann = method.getAnnotation(Citys.class);
    System.out.println(ann.username() + "  " + Arrays.toString(ann.value()) + "  " + ann.annotationType());//包青天  [广州, 深圳]  interface com.bqt.Citys
    System.out.println(ann.toString());//@com.bqt.Citys(username=包青天, value=[广州, 深圳])
    int unused;
}

接口 GenericDeclaration 泛型

public interface java.lang.reflect.GenericDeclaration

所有已知实现类:Class、Constructor、Method
声明类型变量的所有实体的公共接口。

可以声明类型变量的实体的公共接口,也就是说,只有实现了该接口才能在对应的实体上声明(定义)类型变量,这些实体目前只有三个:Class、Construstor、Method(不包含Field类)。

注意:因为直接实现子类没有Field类,所以属性上面不能定义类型变量。

唯一的方法
TypeVariable<?>[] getTypeParameters()

  • 返回声明顺序的 TypeVariable 对象的数组,这些对象表示由此 GenericDeclaration 对象表示的一般声明声明的类型变量。
  • 返回:表示由此一般声明声明的类型变量的 TypeVariable 对象的数组
  • 如果底层的一般声明未声明任何类型变量,则返回一个 0 长度的数组。
public class Test {

    public static <T extends Person, U> void main(String[] args) throws Exception {
        Method method = Test.class.getMethod("main", String[].class);
        TypeVariable<?>[] tvs = method.getTypeParameters();//返回声明顺序的 TypeVariable 对象的数组
        System.out.println("声明的类型变量有:" + Arrays.toString(tvs));//[T, U] ​

        for (TypeVariable<?> tv : tvs) {
            GenericDeclaration gd = tv.getGenericDeclaration(); //GenericDeclaration和TypeVariable两者相互持有对方的引用
            System.out.println(gd);//public static void Test.main(java.lang.String[]) throws java.lang.Exception
            System.out.println(tv + "," + tv.getName() + "," + Arrays.toString(tv.getBounds()));//T,T,[class com.bqt.Person] 和 U,U,[class java.lang.Object]
        }
    }
}

演示代码中用到的Bean
package com.bqt;
​
import java.io.Serializable;
​
public class Animal implements Serializable {
    private static final long serialVersionUID = 1L;
    public int sex;
    private boolean canFly;
​
    public Animal() {
    }
​
    public Animal(int sex, boolean canFly) {
        super();
        this.sex = sex;
        this.canFly = canFly;
    }
​
    private int getSex() {
        return sex;
    }
​
    public void speak(String word) {
        System.out.println("sex:" + sex + "  canFly:" + canFly + "         " + word);
    }
​
    public interface IEat {
        void eat();
    }
}
package com.bqt;
​
import java.io.Serializable;
​
public class Person extends Animal implements Cloneable, Serializable {
    private static final long serialVersionUID = 1L;
    public int age;//公共成员
    private String name;//私有成员
​
    public String getName() {
        return name;
    }
​
    public Person() {//无参构造方法
        super();
    }
​
    private Person(int age) {//私有构造方法
        super();
        this.age = age;
    }
​
    public Person(String name, int age) {//有参构造方法
        super();
        this.age = age;
        this.name = name;
    }
​
    private void privateMethod() {//私有方法
        System.out.println("私有方法:" + name);
    }
​
    public void show() {//公共方法
        System.out.println("公共方法");
    }
​
    public void paramMethod(int num) {//有参方法
        System.out.println("有参方法,参数为:" + num);
    }
​
    public static void staticMethod() {//静态成员
        System.out.println("静态成员");
    }
​
    private class Car {
    }
​
    public interface IRun {
        void run();
    }
}

2017-8-31