Java学习笔记十
11.
一點一點的來
Class類中有一個forName(String className)方法,向方法中傳入包中完整的類名,當然要是字符串類型的,說過反射是運行期的行為,在編譯的時候編譯器當然只會認為你傳入的只是字符串而已;由于返回類名,所以生成一個Class類型的實例來接收
?
12.
對于一個Class類來說里面的方法是值得深究的,是因為有一個類,它的名字就是Class,不要搞混了,Class類中有一個方法,
Methdo[]?getDeclareMethods(),即返回一個Method類型的數組,那么Method又是怎樣的呢:他是一個定義在reflect下的一個類,它有自己的toString方法,就是打印出當前所指的方法名:
加上數組之后就是要打印出目標類中的所有方法,
來看一下下面的程序:
?
package com.jianjian2;
?
import java.lang.reflect.Method;
?
public class ReflectTest
{
?? public static void main(String[]args)throws Exception
?? {
????? Class <?>classType?= Class.forName("java.lang.String");
????? Method[] method = classType.getDeclaredMethods();
????? for(Method meth : method)
????? {
??????? System.out.println(meth);
????? }
?????
?????
?? }
}
?
13.
反射的第一步永遠是獲得要操作類的對象。然后是方法。
?
14.
關于泛型中的模糊繼承,我們常常會見到
T?extends? superClass 的語句,為什要采用這種方式呢?其實只定義T 意義是不大的,我們常常會用不確定的類,但是想調用確定的方法,在泛型中我們可以采用繼承父類或者接口來實現這種設想
比如說,我想定義一個類型,我希望里面有一個 compareTo()方法,而我們知道compareTo方法是接口 Comparable 中的,子類有很多,所以我們可以這樣限制? ArrayList<T extends Compareble> 這樣就可以往動態數組中添加實現了compareble的類型了,而且可以使用里面定義的方法。
看一下例子:
package com.jianjian2.Reflection;
?
public class GeniericTest6
{
?? public static void main(String[] args)
?? {
????? People<String> people = new People<String>("a","n");
????? String[] s = {"a","b","vc"};
????? people.method(s);
?????
?? }
}
?
class People<TextendsComparable>
{
?? private T s1;
?? private T s2;
?? public People(T s1, T s2)
?? {
????? this.s1 = s1;
????? this.s2 = s2;
?????
?? }
?? public T getS1()
?? {
????? return s1;
?? }
?? public void setS1(T s1)
?? {
????? this.s1 = s1;
?? }
?? public T getS2()
?? {
????? return s2;
?? }
?? public void setS2(T s2)
?? {
????? this.s2 = s2;
?? }
?? public? void method(T[] t)
?? {
????? for(inti= 0;i < t.length;i ++)
????? {
??????? System.out.println(t[i].compareTo(t[i]));
????? }
?? }
??
??
}
?
15.
Java里的對象是不能直接拿來用的,我們只能使用指向對象的實例來操作類:
在反射中我們除了要生成類對象之外,別忘了還要生成對象的實例;
反射生成的對象,想當于Class 它的作用就是使用里面的方法,但是類里面具體定義的方法只能使用實例來調用。
總之感覺反射是一步一步的來的:
看下面的程序:
?
/*
?*在一個類中定義一個方法,利用反射來調用這個方法
?* 首先要用到類,肯定要生成類的對象,要用到類中的方法,肯定要生成對象的實例、
?* 想要調用對象的方法,肯定要生成方法對象(Object):其實反射中位于Java.lang.reflect包下的類其實只是為我們提供了指示
?* 我們需要自己定義object來接受那些類提供的信息
?*
?*/
?
package com.jianjian7;
?
import java.lang.reflect.Method;
?
public class InstanceOfTest
{
?? public static void main(String[]args)throws Exception
?? {
????? Class<?>c = Student.class;//生成一個Student對象;
????? Objectinstance = c.newInstance();//生成對象的實例;
????? MethodaddMethod = c.getMethod("method1",new Class[] {int.class,int.class});
????? System.out.println(addMethod);
//打印這個方法的話,會打印出方法的詳細名稱,路徑加上方法名
//public int com.jianjian7.Student.method1(int,int)
????? //調用Class類中此方法,目的是要確定調用那一個方法參數一表示方法的字符串名,后面的可變參數表示有參數類型所構成的Class類型的數組;
????? //防止方法重載;
????? Object result= addMethod.invoke(instance,new Object[]{1,2});//生成一個方法對象指向指定的方法
????? //參數一是對象實例,后面的是為方法添加參數對象的數組;
???? System.out.println((Integer)result);//打印方法會直接調用方法,這點是值得注意的;
?????
?????
?????
?????
?? }
??
}
class Student
{
??
?? public int method1 (int i,int j)
?? {
????? System.out.println(? i + j);
????? return i + j;
?? }
??
}
?
?
16.
反射中獲得類的對象的方式有幾種,注意總結
17.
抽象方法充當著占位的作用。
?
18.‘
鞏固一下泛型 典型的運用:
package com.jianjian2.Generic;
?
public class GenericTest
{
?? public static void main(String[] args)
?? {
?????
??
?? Person<String, Integer > s = new Person<String, Integer >();
?? String s1 = "zhangsan";
?? int s2 = 6;
?? s.setName(s1);
?? s.setAge(s2);
?? System.out.println(s.getName());
?? System.out.println(s.getAge());
?? }
??
??
??
}
class Person <T,K>
{
?? private T name;
?? private K age;
?? public T getName()
?? {
????? return name;
?? }
?? public void setName(T name)
?? {
????? this.name = name;
?? }
?? public K getAge()
?? {
????? return age;
?? }
?? public void setAge(K age)
?? {
????? this.age = age;
?? }
??
}
?
19.
可是要理解好這句話的意思啊:
獲取某個類或某個對象的所對應的Class對象的三種方式:
a) 使用Class類的靜態方法forName(“具體類名”);
b) 使用類?的.class語法:String.class;
c) 使用對象的getClass()方法:String? s = “a”;Class <?>
C = s.getClass? 記住嘍是獲得Class對象!
?
?
19.
?Class 提供的getMethod方法是用來調用對象的方法,其中有一個 newInstance() 方法是新生成實例,也是新生成了構造方法,但是這個構造方法只能是不帶參數的構造方法,如果向往構造參數里面傳入參數的話就要使用別的方式了
?
?
:要想生成帶參數的構造方法,需要調用位于java.lang.reflection下的Constructor類的newInstance()方法,里面要接收參數,還有就是 方法會返回一個 Countructor類型的數據,要調用這個數據還必須通過Class類的getCountructor方法。
意思就是我得到了 Countructor 對象,還要找到一個接受它的實例;
20.
感覺就是反射調用方法,構造方法,類名,在方式上是大同小異的,具體來說
第一步: 首先獲得目標類的Class對象,具體三種方法
第二步:? 假設調用構造方法(通用),首先通過Class對象來調用你要使用什么,方法還是構造方法還是域,這里當然選擇構造方法,Class返回來的都是一個梗概對象,reflection下還有接應Class返回的梗概,同一標識為 Object
?
?
若想通過類的不帶參數的構造方法來生成對象,我們有兩種方式:
a)先獲得Class對象,然后通過該Class對象的newInstance()方法直接生成即可:
Class<?>classType = String.class;
Objectobj = classType.newInstance();
b)先獲得Class對象,然后通過該對象獲得對應的Constructor對象,再通過該Constructor對象的newInstance()方法生成:
?
Class<?>classType = Customer.class;
Constructorcons = classType.getConstructor(new Class[]{});
Objectobj = cons.newInstance(new Object[]{});
4.若想通過類的帶參數的構造方法生成對象,只能使用下面這一種方式:
?
Class<?>classType = Customer.class;
Constructorcons = classType.getConstructor(new Class[]{String.class, int.class});
Objectobj = cons.newInstance(new Object[]{“hello”, 3});
5.Integer.TYPE返回的是int,而Integer.class返回的是Integer類所對應的Class對象。
?
21.
看下列程序 描述分別利用三種方法調用Person的Class對象
?
?
package com.jianjian2.Reflection;
?
public class ReflectionTest3
{
?? public static void main(String[] args )throws Exception
?? {
????? Class<?> c1 = Person.class;
????? Personperson = new Person();
????? Class<?> c2 = person.getClass();
????? Class<?> c3 = Class.forName("com.jianjian2.Reflection.Person");
????? System.out.println(c1);
????? System.out.println(c2);
????? System.out.println(c3);
?? }
}
class Person
{
?? public Person()
?? {
????? System.out.println("xi wang nixing fu ...");
?????
?? }
?? public Person(String i,int j)
?? {
????? System.out.println(i);
????? System.out.println(j);
?? }
}
?
看打印結果
:class com.jianjian2.Reflection.Person
classcom.jianjian2.Reflection.Person
class com.jianjian2.Reflection.Person
顯然是相同的!
22.
具體演示調用? 通用構造方法(即 可以接收帶和不帶參數的構造方法)
:
package com.jianjian2.Reflection;
?
import java.lang.reflect.Constructor;
?
public class ReflectionTest3
{
?? public static void main(String[] args )throws Exception
?? {
????? Class<?> c1 = Person.class;
????? Person person = new Person();
????? Class<?> c2 = person.getClass();
????? Class<?> c3 = Class.forName("com.jianjian2.Reflection.Person");
????? System.out.println(c1);
????? System.out.println(c2);
????? System.out.println(c3);
????? Constructor con = c1.getConstructor(new Class[]{String.class,int.class});
????? //與調用Method不同的是不用使用字符串指定大體是那個方法名,因為構造函數由參數類型數量區分;
????? Object obj = con.newInstance(newObject[]{"wohenxiangni",36});
????? System.out.println(obj);
//我們還可以這樣寫只需要一步:
//Object obj =c1.getConstructor(new Class[] {String.class,int.class}).newInstance(newObject[] {“wohenxiangni”, 36});
?
?????
?????
?? }
}
class Person
{
?? public Person()
?? {
????? System.out.println("xi wang nixing fu ...");
?????
?? }
?? public Person(String i,int j)
?? {
????? System.out.println(i);
????? System.out.println(j);
?? }
}
?
有幾點是要說明一下的
1. 構造方法在生成的時候即已經被調用了;所以程序紅色部分就算沒有前半部分一樣調用構造方法打印? I j;
2. 最后打印Obj 肯定是調用父類 toString方法,所以別指望打印出 I j ;
打印結果:
xi wang ni xing fu ...
classcom.jianjian2.Reflection.Person
classcom.jianjian2.Reflection.Person
classcom.jianjian2.Reflection.Person
wohenxiangni
總結
- 上一篇: Java学习笔记九
- 下一篇: Java学习笔记十五