Class 类代表类的类。每个 Class 类的实例,都代表了一个类。
每个类在 jvm 中都对应一个 Class 对象。jvm 将要使用的 Class 对象加入到类加载器中。
- java 程序运行前,并不会将所有的 Class 对象放入 jvm 中;
- 每个 .class 类在 jvm 中只会对应一个 Class 实例对象;
- Class 对象只能由 jvm 创建和加载;
- Class 对象功能:运行时提供和获取某个对象的类型信息。
.getClass()
与 类名.class
与 Class.forName("类的全限定名")
对象.getClass()
是 Object 类的方法,返回这个对象的类型(注意,这里是指这个实际对象的类型,而非指向这个对象的引用的类型)。即:
// 包 test 中
package test;public class A{}
public class B extends A{}
// 调用类
public class TestUse{public static void main(String[] args){A a = new B();System.out.Class()); // class B}
}
类名.class
返回的和 对象.getClass()
返回的,以及 Class.forName("类的全限定名")
返回的,都是类型(Class 实例对象)。
Class clazz1 = A.class; // 获得 class A
Class clazz2 = a.getClass(); // 获得 class B
Class clazz3 = Class.forName("test.B"); // 获得 class B
.getName()
与 .getSimpleName()
.getName(); // 返回这个类的全限定名,如:java.lang.Thread
.getSimpleName(); // 返回这个类的简单类名(不含包名),如:Thread// 需要用 Class 类的实例来调用,而不能用某个类的类名直接调用。
Dog dog = new Dog();
Class a = Class();
a.getName();
a.getSimpleName();// Name() 是非法的,因为这种调用方式的意思是调用 Dog 类里面定义的 getName() 静态方法,但.getName() 不是定义在该类里的静态方法,也不是 Object 类里的静态方法(如果是的话就自动继承到 Dog 中,那么就真可以调用了,但事实上 .getName() 并没有在 Object 类中定义)。
.newInstance()
不能有参数,返回的是一个 Object 类型的对象。
含义:调用该类的无参构造方法,如果不存在无参构造方法,则报错。
A a = new A();
// 等价于
Class clazz = Class.forName("package.A");
A a = (wInstance(); // 若不强制转换,由于返回的是 Object 实例,无法赋值给 A 类,会报错。
new | .newInstance() | |
---|---|---|
构造方法 | 可以调用任意构造方法 | 只能调用无参构造方法 |
类型 | 确定的类型,写死在代码中 | 类型可以是不确定的,可以动态获取某个类的 Class 实例(比如从txt、xml文件中获取类的全限定名),再创建对象 |
.getField()
通过一个类的 Class 实例,可以获取一个类的成员变量/静态变量(注意是成员变量/静态变量,而非成员变量/静态变量的值)。
注意:
取得的是类的成员变量/静态变量,它是脱离具体对象存在的,即便获取过程中涉及从某些对象中“取出”的过程。甚至如果存在类继承链,从这个父类或子类取出的成员变量/静态变量名甚至是脱离具体类存在的(当然是指当前类继承链中,如果是一个毫不相干的类中即便也有同名同类型属性,也是取不到的)。
这个成员变量得是 public 访问修饰符修饰的,其他访问修饰符会取不到该字段。
Field xxfield = Class类的实例.getField("属性名");Dog dog = new Dog();
Class a = Class();
Field abc = a.getFiled("name"); // 取得类中的 name 成员变量/静态变量.getName(); // 返回变量名
.getType(); // 返回变量的类型
.getDeclaringClass(); // 返回定义该变量的类
.getInt(对象); // 以 int 类型来返回对象的该属性的值,不能自动转换的话会报错
.getDouble(对象); // 以 double 类型来返回对象的该属性的值,不能自动转换的话会报错
.getBoolean(对象); // 以 boolean 类型来返回对象的该属性的值,不能自动转换的话会报错
.get(对象); // 返回该对象的该属性(不管是类型)
.get(null); // 对于静态变量,可以直接传 null 来取得静态变量的值;但如果是取成员变量的属性值,传入null是会报错的。
.set(对象,新属性值); // 将该对象的该属性设定为这个新的属性值
.setAccessible(true); // 将非 public 的属性改为可访问(对 public 属性无效,设置为 false也仍旧能访问)// 例子
Name();
Type();
DeclaringClass();
Int(dog);
(dog);
(null);
abc.set(dog,"Tom");Field abb = a.getDeclaredField("age"); // age 为 private 属性,可以通过 .getDeclaredField() 取得
abb.setAccessible(true);
.getMethod()
通过一个类的 Class 实例,可以获取一个类的方法。
Method xxmethod = Class类的实例.getMethod("方法名",形参类型依顺序排列);
// 若形参为可以变长参数,如 abc,则写为 String[].classDog dog = new Dog();
Class a = Class();
Method abc = a.getMethod("buy",String.class,int.class); // 取得类中方法签名为 buy(String,int) 的方法。.getName(); // 返回方法名
.getReturnType(); // 返回方法的返回类型
.getParameterTypes(); // 返回方法形参的 Class 类型数组(哪怕只有一个形参类型)
.getParameterCount(); // 返回方法形参的个数(可变长参数只算一个参数)
.invoke(对象,按形参顺序依此传递实参); // 对该对象调用该方法
.invoke(null,按形参顺序依此传递实参); // 调用静态方法
.setAccessible(true); // 将非 public 的方法改为可访问(对 public 方法无效,设置为 false也仍旧能访问)// 例子
Name();
ReturnType();
abc.invoke(dog,"Tom",3);Method abb = a.getDeclaredMethod("buy"); // age 为 private 属性,可以通过 .getDeclaredField() 取得
abb.setAccessible(true);
可以使用反射(reflection)来访问属性。
反射其实是基本所有高级语言都提供的一个功能,它提供了一种相对动态的方式来获取属性和调用方法。
用反射可以访问和设置属性,还能调用方法,甚至比 对象.属性/方法
这种访问更特殊的是,反射可以访问到 private 的属性和方法。
private 的设置其实并不是为了安全性,而是为了更好地封装,让结构更加清晰。
如果说反射和对象.属性/方法
还有什么区别的话,就是访问效率。反射实际上是走的迂回路线,所以效率没有 对象.属性/方法
的方式高。但这个“效率低”只是指迂回地去建立反射的过程,一旦建立了反射(比如说已经获得了 method),你去调用的话(传入对象和实参),其实不存在效率更低的。所以一般大量使用反射的时候,会把“提取”出来的 method 和 field 都保存起来,然后再用这个 method 和 field 来调用相应的对象和传入参数,这样就不会慢了(只有“提取”的那一步比较慢)。
提取方法时,需要这个 Class 实例所对应的类中定义了该方法(拥有该方法签名),才能提取;
提取方法后,只能用这个提取的类,或其子类的对象来调用(因为这个对象中有这个方法签名的方法)
若子类中有对该方法的覆盖,则调用子类对象时,调用的是该方法的覆盖方法(这就比较巧妙了,仍然是遵守”覆盖多态“的);
但若用当前类的对象调用,则无论子类中是否对该方法进行覆盖,都不影响当前类的对象调用的是当前类的方法。
注意:若此处,父类是 private,子类变为 public 方法签名和返回值一致,并不算发生“覆盖”。父类的该方法与子类的该方法被视作两个完全不同的方法。(假如用 setAccessible 更改父类 private 方法为可访问,并不会出现”覆盖多态")
另外,当前类提取的方法覆盖了其父类的方法的话,用父类对象来调用这个当前类提取的覆盖方法是会报错的。
【静态方法】静态方法则例外,无论是父类还是子类中提取的静态方法(仅仅继承,没有覆盖),都可以随意用父类或子类的对象调用,也可以直接用 null 调用。
【静态方法】静态方法如果发生了覆盖,则从无论是父类或子类中提取的静态方法,都可以随意用父类或子类的对象调用,也可以直接用 null 调用。但最终调用哪个静态方法,取决于这个静态方法是从哪个类中提取的,与具体用什么对象来调用无关。
st.classtest;import java.util.Objects;public class Dog {private String name;private String nickname = "little Tom";public int age = 8;public int size = 10;double weight;protected boolean live = true;public static String blood;public static int number = 101;public Dog(String name) {this.name = name;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (!(o instanceof Dog)) return false;Dog dog = (Dog) o;return name.equals(dog.name);}@Overridepublic int hashCode() {return Objects.hash(name);}@Overridepublic String toString() {return "Dog{" +"name='" + name + ''' +'}';}public void sayHi() {System.out.println(this.name + " : Hi~");}public int sayHello(String dogname) {System.out.println("Hello~ " + dogname);return 1;}public int sayHello(String dogname, int dogage) {System.out.println("Hello~ " + dogname + " is " + dogage + " years old.");return 2;}public void words) {System.out.print("数组(" + words + ")长度: " + words.length + "。t");for (String a : words) {System.out.print(a + "t");}System.out.println();}private void cry() {System.out.println(this.name + " : wooo~");}private void cryOverride(){System.out.println("这是 Dog 中的 ");}protected void cryProtect(){System.out.println("");}void cryDefault(){System.out.println("");}public static void sayWow(String dogname) {System.out.println("Wow~ " + dogname);}public static void sayOops() {System.out.println("这是Dog的静态方法 sayOops");}
}st.classtest;public class Doggy extends Dog {public double height = 50;public int size = 5;public Doggy(String name) {super(name);}public int sayHello(String dogname, int dogage, double weight) {System.out.println("Hello~ " + dogname + " is " + dogage + " years old and weights "+weight+" kilogram.");return 2;}public void sayHi() {System.out.println("Hi~这是 Doggy 的 sayHi");}public static void sayOops(){System.out.println("这是 dog 的静态方法 sayOops");}public void cryOverride(){System.out.println("这是 Doggy 中的 ");}
}st.classtest;public class Cat {public int age;public int sayHello(String catname, int catage) {System.out.println("Hello~ " + catname + " is " + catage + " years old.");return 2;}
}// 调用类
st.classtest;import flect.Field;
import flect.InvocationTargetException;
import flect.Method;public class TestUse {public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException, InvocationTargetException {Dog dog = new Dog("Tom");// 由于 class 是关键字,所以一般会改写为 clazzClass clazz = Class();System.out.println(clazz); // st.classtest.DogClass clazz2 = Dog.class;System.out.println(clazz2); // st.classtest.DogSystem.out.Name()); // st.classtest.DogSystem.out.SimpleName()); // Dog// .getField()// Field nameField = Field("name"); // 因为 name 在 Dog 类中是 private,所以直接这样调用会报错 NoSuchFieldException// Field weightField = Field("weight"); // 因为 weight 在 Dog 类中是缺省的访问修饰符,而非 public,所以直接调用仍然报错 NoSuchFieldException// Field liveField = Field("live"); // live 在 Dog 类中是 protected 而非 public,直接调用报错 NoSuchFieldException// 而 age 在 Dog 类中是 public,所以可以访问得到Field ageField = Field("age");System.out.println(ageField); // public st.classtest.Dog.age// 取得属性名System.out.Name()); // age// 取得属性类型System.out.Type()); // int// 返回定义该属性的类,注意是这个定义的所在类,如果是在父类中定义的,返回的是该父类。System.out.DeclaringClass()); // st.classtest.DogSystem.out.Double(dog)); // 8.0
// System.out.Boolean(dog)); // 报错,因为 int 无法转换成 booleanSystem.out.Int(dog)); // 8System.out.(dog)); // 8
// System.out.(null)); // 报错,因为 null 没有这个属性值
// System.out.println("强制类型转换:"((Dog)null)); // 报错,仍旧无法取到属性(这也是显然的,因为 null 就是没有属性)// 只要是 public 修饰的,静态变量也是可以取到的。Field bloodField = Field("blood");System.out.println(bloodField); // public static java.lang.st.classtest.Dog.bloodSystem.out.Type()); // class java.lang.StringField numberField = Field("number");// 即便 number 是静态变量,也可以使用 .get类型(对象) 来返回值System.out.Int(dog)); // 101System.out.(dog)); // 101System.out.println(dog.number); // 101System.out.println(Dog.number); // 101System.out.(null)); // 101// 即对于静态变量,可以直接传 null 就可以取得。当然,传类的对象也是可以取得的。Dog doggy = new Doggy("Mark");Class clazzdoggy = Class();Field doggyAge = Field("age");// 因为 age 是在父类 Dog 中定义的,所以返回的是 DogSystem.out.DeclaringClass()); // st.classtest.DogField doggyHeight = Field("height");System.out.DeclaringClass()); // st.classtest.DoggySystem.out.println("小狗高度: " + (doggy)); // 小狗高度: 50.0
// System.out.println("大狗高度:"(dog)); // 报错,因为父类 Dog 中没有这个属性// ageField 与 doggyAge 虽然从不同对象中获得,但实际是同一个变量,所以可以混用调用对方类的实例对象System.out.Int(doggy)); // 8System.out.Int(dog)); // 8System.out.(dog)); // 8System.out.(doggy)); // 8// 即子类中直接继承父类的属性,那么子类或父类中提取的属性,可以被对方的对象相互混调。ageField.set(dog, 12);System.out.println("修改年龄后: " + (dog)); // 修改年龄后: 12System.out.(doggy)); // 8// 即,子类中继承的父类属性,的确是子类中的,而不是父类中的,子类可以调用用父类提取的属性来获取子类的属性。doggyAge.set(dog, 11);System.out.println("修改年龄后: " + (dog)); // 修改年龄后: 11System.out.println("修改年龄后: " + (dog)); // 修改年龄后: 11System.out.(doggy)); // 8// 即,的的确确对于继承的属性,无论从子类还是父类中提取得到的属性,地位是一样的,可以被父类对象或子类对象调用。Field dogsize = Field("size");Field doggysize = Field("size");System.out.println("大狗体型:" + (dog)); // 大狗体型:10System.out.(doggy)); // 10// 即,发生子类属性与父类属性重名时,父类提取的属性,以子类对象来调用的话,实际上取到的并非为子类属性值,而是父类属性值System.out.println("小狗体型:" + (doggy)); // 小狗体型:5
// System.out.(dog)); // 报错,因为这个属性值不是 Dog 中的属性值(即便同名,但等于没有被定义)// 即,当发生子类与父类属性值同名,子类提取的属性只能被子类的对象调用,并不能被父类对象调用。Cat cat = new Cat();
// System.out.Int(cat)); // 报错,因为这个 age 属性是 Dog/Doggy 类中的 age,不是 Cat 中的 age。System.out.Fields()); // [flect.Field;@7699a589// 返回的是一个 Field 的数组对象// 用下方的静态方法 printFields() 查看一下类的所有属性(可以看到,能取到的,都是 public 修饰的)printFields(clazz);/*st.classtest.Dog里的 fieldint ageint sizeclass java.lang.String blood // 可以看到静态变量 blood 也被打印出来了int number // 还有静态的 number*/printFields(clazzdoggy);/*st.classtest.Doggy里的 fielddouble heightint sizeint ageint sizeclass java.lang.String bloodint number*/// 可以看到子类的属性包括了所有从父类中继承的属性。// .getField() vs. .getDeclaredField()// Field nameField = Field("name"); // 因为 name 在 Dog 类中是 private,所以直接这样调用会报错 NoSuchFieldExceptionField nameField = DeclaredField("name");
// System.out.(dog)); // 报错,无法访问 private 修饰的属性
// Field weightField = Field("weight"); // 因为 weight 在 Dog 类中是缺省的访问修饰符,而非 public,所以直接调用仍然报错 NoSuchFieldExceptionField weightField = DeclaredField("weight");
// System.out.(dog)); // 0.0// 即可以访问 缺省 访问修饰符的属性,当然前提得是调用类和 Dog 类在同一个包中,尝试过将它们放到不同包,取 declaredField 不报错,但再进一步取值就报错了。// 如果时放到不同包,经过测试,可以通过下面的方式获取到属性值
// weightField.setAccessible(true);
// System.out.(dog)); // 0.0
// System.out.(doggy)); // 0.0// Field liveField = Field("live"); // live 在 Dog 类中是 protected 而非 public,直接调用报错 NoSuchFieldExceptionField liveField = DeclaredField("live");
// System.out.(dog)); // true// 即可以访问 protected 访问修饰符的属性。但仍然需要得调用类和 Dog 类在同一个包中,尝试过将它们放到不同包,取 declaredField 不报错,但再进一步取值就报错了。// 如果放到不同包,经过测试,可以通过下面的方式获取到属性值
// liveField.setAccessible(true);
// System.out.(dog)); // true
// System.out.(doggy)); // truenameField.setAccessible(true);System.out.(dog)); // Tom// 即更改 private 的属性的访问权限为 true 后,就可以获得该属性值了。且这种改变是对可以调用这个属性的所有对象都有效,而不仅仅是提取该属性时的当前类。System.out.(doggy)); // Mark// 这里的神奇之处在于,Doggy 继承 Dog,但 name 属性在 Dog 中是 private ,理论上是继承不了的,但显然这里就等于说事情没有这么简单...毕竟的确构造方法里有一个 this.name 的赋值。// 下面尝试一下完全没有在子类中赋值的 private 属性,看能不能用子类对象调用。Field nickNameField = DeclaredField("nickname");nickNameField.setAccessible(true);System.out.(dog)); // little TomSystem.out.(doggy)); // little Tom// 发现实际上 Doggy 还真就继承了 Dog 的 private 的 nickName 属性。而 name 之所以还能有自己的值,是因为构造方法里 this.name 赋值了 子类对象的 name 属性值。nameField.setAccessible(false);
// System.out.(dog)); // 报错,无法访问 private 属性。weightField.setAccessible(false);
// System.out.(dog)); // 0.0// 缺省 访问修饰符修饰的属性,类与调用类在同一个包中时,设置成不可访问还是可以访问,但如果是放到不同包中,则会报错。即能重新设置成不能访问liveField.setAccessible(false);
// System.out.(dog)); // true// protected 访问修饰符修饰的属性,类与调用类在同一个包中时,设置成不可访问还是可以访问,但如果是放到不同包中,则会报错。技能重新设置成不可访问。// 即,被设置为可访问的非public 属性,可以重新设置为不可访问。System.out.(dog)); // 11ageField.setAccessible(false);System.out.(dog)); // 11System.out.(doggy)); // 8// 即,并不能对原本 public 的属性降低访问权限为不能访问。设置了不能访问,还是可以访问的。Field declareAgeField = DeclaredField("age");System.out.(dog)); // 11declareAgeField.setAccessible(false);System.out.(dog)); // 11System.out.(doggy)); // 8// 即,public 属性的确是不能通过 setAccessible 来设置成不可访问,与是用 getField 还是 getDeclaredField 取得的无关。/*综上:用 getDeclareField 取得的属性:public 属性,setAccessible 设置成 false 也无法限制访问。 (用 getField 取得也是如此)private 属性,setAccessible 可以控制是否可以访问缺省 或 protected 属性,若类与调用类在同一个包中,setAccessible 无法控制能否访问,全都可以访问。但若在不同包中,setAccessible 可以用来控制是否可以访问。*/System.out.println("---------------getMethod---------------");Method sayHelloMethod = Method("sayHello", String.class);System.out.Name()); // sayHelloSystem.out.ReturnType()); // intSystem.out.println("sayHelloMethod: " + ReturnType()); // sayHelloMethod: intfor (Class cl : ParameterTypes()) {System.out.Name() + "t"); // java.lang.String}System.out.println();System.out.ParameterCount()); // 1sayHelloMethod.invoke(dog, "Tommy"); // Hello~ TommysayHelloMethod.invoke(doggy, "Timmy"); // Hello~ Timmy// 也就是父类中提取的方法,可以用子类的对象实例来调用(毕竟子类继承了该方法)Method sayHiMethod = Method("sayHi");Method sayHiSonMethod = Method("sayHi");sayHiMethod.invoke(dog); // Tom : Hi~sayHiMethod.invoke(doggy); // Hi~这是 Doggy 的 sayHi// 即父类提取的方法,如果在子类中是被覆盖的,用子类对象调用时执行的是子类的覆盖方法
// sayHiSonMethod.invoke(dog); // 报错:不是该方法声明的所在类的对象// 即子类提取的覆盖方法,并不能被父类对象调用。sayHiSonMethod.invoke(doggy); // Hi~这是 Doggy 的 sayHiMethod sayHelloMethod2 = Method("sayHello", String.class, int.class);System.out.Name()); // sayHelloSystem.out.ReturnType()); // intSystem.out.println("sayHelloMethod2: " + ParameterTypes()); // sayHelloMethod2: [Ljava.lang.Class;@7699a589for (Class cl : ParameterTypes()) {System.out.Name() + "t"); // java.lang.String int}System.out.println();System.out.ParameterCount()); // 2
// sayHelloMethod2.invoke(dog,"Jerry"); // 报错,并没有实现重载
// sayHelloMethod2.invoke(dog,5,"Jerry"); // 报错,因为参数类型不对应sayHelloMethod2.invoke(dog, "Jerry", 5); // Hello~ Jerry is 5 years old.
// sayHelloMethod2.invoke(cat,"Tom",5); // 报错,虽然 Cat 类中又一模一样的方法,但这个方法是 Dog 类中的方法,无法使用 cat 来调用。sayHelloMethod2.invoke(doggy, "Mark", 3); // Hello~ Mark is 3 years old.// Method sayHelloMethod3 = Method("sayHello",String.class,int.class,double.class); // 报错,找不到该方法。这是因为 clazz 是 Dog 类,里面没有定义这个方法签名的重载方法(是在子类 Doggy中定义的)Method sayHelloMethod3 = Method("sayHello", String.class, int.class, double.class);sayHelloMethod3.invoke(doggy, "Mark", 3, 12); // Hello~ Mark is 3 years old and weights 12.0 kilogram.
// sayHelloMethod3.invoke(dog,"Mark",3,15); // 报错。因为 dog 是 Dog 类的实例,不是定义该方法的类(Doggy)的实例。// 即 提取/映射这个方法时,需要这个Class实例所对应的类中得有这个方法签名,并且提取这个方法后,只能用这个类(或子类:因为继承了父类的方法)的实例来调用这个方法。Method equalsMethod = Method("equals", Object.class);System.out.Name()); // equalsSystem.out.ReturnType()); // booleanSystem.out.println("equalsMethod: " + ParameterTypes()); // equalsMethod: [Ljava.lang.Class;@58372a00for (Class cl : ParameterTypes()) {System.out.Name() + "t"); // java.lang.Object}System.out.println();System.out.ParameterCount()); // 1Method sayMethod = Method("sayThing", String[].class);System.out.println("sayMethod: " + ParameterCount()); // sayMethod: 1Method wowMethod = Method("sayWow", String.class);Method wowMethod2 = Method("sayWow", String.class);wowMethod.invoke(dog,"John"); // Wow~ JohnwowMethod.invoke(doggy,"Johnny"); // Wow~ JohnnywowMethod.invoke(null,"Alex"); // Wow~ AlexwowMethod2.invoke(doggy,"Johnny"); // Wow~ JohnnywowMethod2.invoke(dog,"John"); // Wow~ JohnwowMethod2.invoke(null,"Alex"); // Wow~ Alex// 即,子类从父类继承的静态方法,无论是从子类还是父类中提取该静态方法,都可以用父类或子类的对象来调用,也可以直接用 null 调用。Method oopMethod = Method("sayOops");Method oopMethod2 = Method("sayOops");oopMethod.invoke(dog); // 这是Dog的静态方法 sayOopsoopMethod.invoke(doggy); // 这是Dog的静态方法 sayOopsoopMethod.invoke(null); // 这是Dog的静态方法 sayOopsoopMethod2.invoke(doggy); // 这是 dog 的静态方法 sayOopsoopMethod2.invoke(dog); // 这是 dog 的静态方法 sayOopsoopMethod2.invoke(null); // 这是 dog 的静态方法 sayOops// 即,子类覆盖父类的静态方法时,无论方法是从父类还是子类提取的,都可以用父类或子类的对象调用,也可以用 null 调用,但是最终调用哪个方法,取决于方法是从哪个类中提取的,与调用对象无关。// private 方法
// Method cryMethod = Method("cry"); // 报错。因为访问不到 private 方法Method cryMethod = DeclaredMethod("cry");
// cryMethod.invoke(dog); // 报错,没有调用 private 方法的权限。cryMethod.setAccessible(true);cryMethod.invoke(dog); // Tom : wooo~cryMethod.invoke(doggy); // Mark : wooo~cryMethod.setAccessible(false);
// cryMethod.invoke(dog); // 报错,没有调用 private 方法的权限。// 即,可以通过 setAccessible 对 private 方法进行访问控制。
// Method cryProtectMethod = Method("cryProtect"); // 报错,找不到该方法。因为属性不是 publicMethod cryProtectMethod = DeclaredMethod("cryProtect");
// cryProtectMethod.invoke(dog); //
// cryProtectMethod.invoke(doggy); // // 即,当方法所在类和调用类在同一个包中时,可以直接调用 protected 修饰的方法。// 若不再同一个包中,则需要用以下方式访问:cryProtectMethod.setAccessible(true);
// cryProtectMethod.invoke(dog); //
// cryProtectMethod.invoke(doggy); //
// cryProtectMethod.setAccessible(false);
// cryProtectMethod.invoke(dog); // 报错,不能访问 protected 权限的方法// Method cryDefaultMethod = Method("cryDefault"); // 报错,找不到该方法。因为属性不是 publicMethod cryDefaultMethod = DeclaredMethod("cryDefault");
// cryDefaultMethod.invoke(dog); //
// cryDefaultMethod.invoke(doggy); // // 即,当方法所在类和调用类在同一个包中时,可以直接调用 缺省 访问修饰符的方法。// 若不再同一个包中,则需要用以下方式访问:
// cryDefaultMethod.setAccessible(true);
// cryDefaultMethod.invoke(dog); //
// cryDefaultMethod.invoke(doggy); //
// cryDefaultMethod.setAccessible(false);
// cryDefaultMethod.invoke(dog); // 报错,无法调用 缺省 访问修饰符修饰的方法。sayHiMethod.invoke(dog); // Tom : Hi~sayHiMethod.setAccessible(false);sayHiMethod.invoke(dog); // Tom : Hi~Method sayHiDeclareMethod = DeclaredMethod("sayHi");sayHiDeclareMethod.invoke(dog); // Tom : Hi~sayHiDeclareMethod.setAccessible(false);sayHiDeclareMethod.invoke(dog); // Tom : Hi~// 即,对于原本就是 public 修饰的方法,无论是通过 getMethod 还是 getDeclaredMethod 提取的,都不能通过 setAccessible 让它变成不可访问的。Method cryOverMethod = DeclaredMethod("cryOverride");
// cryOverMethod.invoke(dog); // 报错,无法访问 private 方法
// cryOverMethod.invoke(doggy); // 报错。即便 Doggy 中覆盖该方法并且设置为 public 但提取这个方法的类对该方法设置的是 private,所以还是无法调用。cryOverMethod.setAccessible(true);cryOverMethod.invoke(dog); // 这是 Dog 中的 OverMethod.invoke(doggy); // 这是 Dog 中的 // 即,父类的方法假如是 private,而子类变为 public ,实际上并不会形成”覆盖“,所以是视作两个完全不同的方法。所以即便用父类的这个 private 方法设置为可访问后,用子类对象来调用,并不会出现”多态“的情况,而仅仅是调用父类的这个方法。Method cryOverMethod2 = DeclaredMethod("cryOverride");cryOverMethod2.invoke(doggy); // 这是 Doggy 中的
// cryOverMethod2.invoke(dog); // 报错。因为提取的这个方法调用的对象不是当前提取类(或其子类)的实例/*综上:用 getDeclareMethod 取得的方法:public 方法,setAccessible 设置成 false 也无法限制访问。 (用 getMethod 取得也是如此)private 方法,setAccessible 可以控制是否可以访问缺省 或 protected 方法,若类与调用类在同一个包中,setAccessible 无法控制能否访问,全都可以访问。但若在不同包中,setAccessible 可以用来控制是否可以访问。另外其实也发现,实际上,子类是把父类的非 public 方法都继承了。*/// 用下方的静态方法 printMethods() 查看一下类的所有方法printMethods(clazz);/*st.classtest.Dog 里的 methodboolean equals(class java.lang.Object, )class java.lang.String toString()int hashCode()void sayThing(class [Ljava.lang.String;, )void sayWow(class java.lang.String, )void sayHi()int sayHello(class java.lang.String, int, )int sayHello(class java.lang.String, )void sayOops()void wait(long, int, )void wait()void wait(long, )class java.lang.Class getClass()void notify()void notifyAll()*/// 会发现打印出了一些我们没有定义过的方法,也就是这个类本身继承 Object 类的方法也会被打印出来。但注意到这里打印的其实都是 public 修饰的方法。}public static void printFields(Class clazz) {System.out.Name() + "里的 field");for (Field Fields()){System.out.Type()+" "+ Name());}}public static void printMethods(Class clazz){System.out.Name()+" 里的 method");for (Method Methods()){String paratype = "";for(Class cl : ParameterTypes()){paratype += cl +"," +"t";}System.out.ReturnType()+" "Name()+"("+paratype+")");}}
}
用 getDeclareField 取得的属性:
用 getDeclareMethod 取得的方法:
本文发布于:2024-01-28 00:02:29,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17063713663437.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |