Java中的反射和枚举
假設現(xiàn)在上面的數(shù)據(jù)是以二次探測的方式來進行存放的,現(xiàn)在讓你求:
現(xiàn)在找1:直接就能找到----->次數(shù)是1
現(xiàn)在找4:直接就可以找到---->次數(shù)是1
現(xiàn)在找14:先得到4的下標,發(fā)現(xiàn)不是14向后找,這里面用了兩次
現(xiàn)在找24::先得到4的下標,發(fā)現(xiàn)不是24向后找,這里面用了3次
總共找的次數(shù):1+1+2+3+1=8
1)查找成功的平均長度:查找成功的次數(shù)/有效數(shù)據(jù)的長度=8/5;
2)查找不成功的平均長度:
已經(jīng)存在的數(shù)據(jù):查找的這個數(shù)位置開始前一個向后走幾步到空格?2+4+3+2+2=13
沒有存在的數(shù)據(jù)就是1;
0-->1
1--->2
2--->1
3---->1
4---->4
14---->3
24----->2
7------>1
8------>1
9------>2
18/10=1.8;
查找不成功的次數(shù)/數(shù)組的長度
1.反射
1)反射的定義:
1.1)Java中的反射,是指在運行過程中,對于任意的一個類,都可以知道這個類的所有屬性和方法;對于任意一個對象,都可以調(diào)用它的任意的一個方法和屬性,那么既然可以拿到,我們就可以修改部分類型信息;這種動態(tài)獲取信息以及動態(tài)調(diào)用對象的方法的功能稱之為Java語言的反射機制
1.2)所有有關于反射相關的類和相關的包都在java.lang.reflect包下面
2)反射中涉及到的一些常見的類-----重要
反射中在哪里用到,介紹一下(面試--框架)
主要用途:
1)在我們?nèi)粘5牡谌綉瞄_發(fā)過程中,通常會遇到某個類的成員變量,方法或者屬性是私有的或只是系統(tǒng)應用對應開放,這時候我們就可以通過反射獲取所需的私有的成員或者方法
2)反射最重要的就是開發(fā)各種應用型框架,比如在Spring中,我們將所有的類Bean交給Spring容器進行管理,無論是XML配置Bean還是注解配置,當我們從容器中獲取Bean來進行依賴注入的時候,容器會讀取配置,而配置中給的就是類的信息,spring根據(jù)這些信息,需要創(chuàng)建那些bean,spring就動態(tài)的創(chuàng)建這些類
1)Class類:代表類的實體,在運行的java程序中表示類和接口
2)Field類:代表類的成員變量/類的屬性
3)Method類:代表類的方法
4)Constructor類,它是代表類的構造方法
Java被編譯之后,生成了.class文件(此時在磁盤上面),我們要把這個.class運行到JVM的時候,需要通過JAVA命令來進行運行,此時JVM就會要去解讀.class文件,被編譯后的java文件.class最終也被JVM解析成一個類,這個對象就是java.lang.Class,當程序在運行的時候,每一個類就變成了Class對象的一個實例。這樣當程序正在運行的時候,我們通過java的反射機制應用到這個實例,就可以去獲得甚至去改變這個類的屬性和動作,是這個類稱為一個動態(tài)的類;
class Student {//此時構造方法是私有的,我們要想創(chuàng)建對象,只能在類內(nèi)創(chuàng)建,通過方法返回給類外private int age=18;private String name="bit";public Student(){System.out.println("我是這個類中的不帶有參數(shù)的構造方法");}private Student(String name, int age){this.name=name;this.age=age;System.out.println("我是這個類中一個私有的構造方法");}private void start(String str){System.out.println("我是這個類中的帶參數(shù)的普通方法"+str);}private void run(){System.out.println("我是這個類中的不帶有參數(shù)的私有方法");}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}}1)獲取當前的Class對象(通過反射來獲取類對象),此時有三種方式
1)通過Class.forName(里面是路徑)方法
Class<?> C1=Class.forName("Student");//包名.類名 Class<?> C2= Student.class; Student student=new Student(); Class<?> C3=student.getClass(); System.out.println(C1==C2); System.out.println(C2==C3); 不管是用哪種方式來獲取Class對象,這里面的打印結果都是True,說明類對象只有一個2)通過類名.Class返回一個實例
3)先類創(chuàng)建實例,再通過引用.getClass()來進行返回
//1.根據(jù)包全限定類名:Class.forName("類的全路徑名");Class<?> StudentClass1=Class.forName("Demo.Student");//2.使用.class方法Class<?> StudentClass2=Student.class;//3.通過先進行創(chuàng)建對象的實例,在進行獲取類對象Student student=new Student();Class<?> StudentClass3=student.getClass();2.創(chuàng)建對象
類對象的引用.newInstance() 創(chuàng)建一個對象,也就是說通過類對象的newInstance方法來獲取學生實例
//1.先進行獲取到類的類對象 Class<?> C1=Class.forName("Student"); //2.通過反射創(chuàng)建這個類的實例 Student lijiawei= (Student) C1.newInstance();//最重要進行強制類型轉(zhuǎn)換,這樣就可以實例化一個對象 System.out.println(lijiawei); //3.訪問一些信息 System.out.println(lijiawei); 打印結果:我是這個類中的不帶有參數(shù)的構造方法 Student{age=18, name='bit'}要不就直接通過類對象的實例調(diào)用newInstance()創(chuàng)建這個對象的實例
要不就先獲取到構造方法,通過調(diào)用constructer.newInstance方法傳入相關的構造參數(shù)來進行創(chuàng)建實例
3.獲取類中的構造器的方法:
1)getConstructor(Class......<?> parameterTypes)獲得該類中與參數(shù)類型相匹配的公有的構造方法
2)getConstructors()獲取該類的所有的所有的構造方法
3)getDeclaredConstructor(Class<?> parameterTypes)獲取該類中與參數(shù)類型相匹配的構造方法//即可以獲取到公有構造方法,也可以獲取到私有構造方法
4)如果在其中獲取到了私有的構造方法,我們還是需要調(diào)用一下構造器引用.setAccessible()方法,將里面的參數(shù)設置成true
5)getDeclaredConstructors() 獲取該類的所有構造方法
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {//現(xiàn)在我們想獲取到Student類的私有構造方法//1.先獲取到類對象Class<?> ClassStudent=Class.forName("Demo.Student");//2.獲取到構造方法Constructor<Student> constructor= (Constructor<Student>) ClassStudent.getConstructor(String.class,int.class);//里面?zhèn)魅霕嬙旆椒ň唧w的參數(shù)類型.class//3.調(diào)用構造方法,傳入相應的參數(shù),創(chuàng)建對應的實例Student student=constructor.newInstance("李佳偉",90);System.out.println(student);//上面的代碼直接運行會報錯,因為我們調(diào)用的是私有的構造方法,為了體現(xiàn)封裝的安全性,我們應該再加上一條語句}現(xiàn)在這么寫就好了:
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {//現(xiàn)在我們想獲取到Student類的私有構造方法//1.先獲取到類對象Class<?> ClassStudent=Class.forName("Demo.Student");//2.獲取到構造方法Constructor<Student> constructor= (Constructor<Student>) ClassStudent.getDeclaredConstructor(String.class,int.class);//里面?zhèn)魅霕嬙旆椒ň唧w的參數(shù)類型.class//3.調(diào)用構造方法,傳入相應的參數(shù),創(chuàng)建對應的實例constructor.setAccessible(true);//可以使用構造方法Student student=constructor.newInstance("李佳偉",90);System.out.println(student);//上面的代碼直接運行會報錯,因為我們調(diào)用的是私有的構造方法,為了體現(xiàn)封裝的安全性,我們應該再加上一條語句}4.反射私有的屬性(可以獲取私有的,獲取公開的)
1)getField(String name) 獲得某一個共有的屬性對象
2)getFields()獲取到所有的共有的屬性對象
3)getDeclaredField(String name)獲取到某一個屬性對象,返回值是一個Field對象
4)getDeclaredFields()獲取到所有的屬性對象
//現(xiàn)在我們想獲取到Student類的私有構造方法//1.先獲取到類對象Class<?> ClassStudent=Class.forName("Demo.Student");//2.獲取到構造方法構造對象Constructor<?> constructor=ClassStudent.getDeclaredConstructor(String.class,int.class);constructor.setAccessible(true);Student student=(Student)constructor.newInstance("李佳偉",12);//3.獲取到類里面的字段Field filed1=ClassStudent.getDeclaredField("name");//里面填寫字段名Field filed2=ClassStudent.getDeclaredField("age");filed1.setAccessible(true);filed2.setAccessible(true);//4.進行修改私有字段和屬性filed1.set(ClassStudent,"張志超");filed2.set(ClassStudent,81);//第一個參數(shù)填寫這個對象的引用,第二個參數(shù)寫要修改成為的具體的字段名System.out.println(filed1);System.out.println(filed2);?5.反射類中的方法
1)獲取某個類中共有的方法:getMethod(),里面的參數(shù)是方法名,參數(shù)類型.class,最終返回的是Method對象 2)獲取到該類中所有的方法:getMethods() 3)獲取到該類中的某一個方法getDeclaredMethod(String name,Class....<?> parameterTypes) 4)獲取到該類中的所有方法:getDeclaredMethods(); method.invoke(對象名,字段值)我們最重要調(diào)用這個方法來進行調(diào)用我們獲取到的方法 //1.先進行獲取到類對象Class<?> classStudent=Student.class;//2.獲取到私有的構造方法Constructor<?> constructor= classStudent.getDeclaredConstructor(String.class,int.class);//3.創(chuàng)建具體的對象constructor.setAccessible(true);Student student=(Student)constructor.newInstance("張中軍",90);//4.獲取到對應的方法Method method= classStudent.getDeclaredMethod("start",String.class);method.setAccessible(true);//5.調(diào)用對應的獲取到的方法method.invoke(student,"sb");2.枚舉?
1)背景以及定義:
枚舉是在JDK1.5之后進行引入的,目的用途是將一組常量組織起來,在這之前表示一組常量通常使用定義常量的方式例如:
public static final int RED=1;
public static final int GREEN=2;
public static final int BLACK=3;
但常量枚舉有一個不好的地方,例如假設現(xiàn)在正好有一個數(shù)字1,但是他可能會被誤認為是RED,現(xiàn)在我們可以直接使用枚舉來進行組織,這樣一來就擁有了枚舉類型而不是一個普通的數(shù)字1;
public enum TestEnum{RED,BLACK,GREEN;public static void main(String[] args]{System.out.println(TestEnum.RED);//在類外要通過類名.的方式System.out.println(BLACK);}}此時打印出來的值就是RED,BLACK public enum TestEnum{RED,BLACK,GREEN;public static void main(String[] args){TestEnum testEnum=TestEnum.BLACK;switch (testEnum){case RED:System.out.println("red");break;case BLACK:System.out.println("black");break;case GREEN:System.out.println("green");break;}}}2.Enum中的常見方法(自己寫的枚舉類,默認繼承了一個抽象類Enum,public abstract class<E extends Enum<E>> implements Comparable<E>,Serializable;
1)values()以數(shù)組的形式返回枚舉類型的所有成員
2)ordinal()獲取到枚舉成員的索引位置--------在Enum類里面
3)valueOf()將普通字符串轉(zhuǎn)化成枚舉實例
4)compareTo()比較兩個枚舉成員定義的順序,默認是通過索引來進行比較的
public enum TestEnum{RED,BLACK,GREEN,WHITE;public static void main(String[] args) {TestEnum[] arr1=TestEnum.values();for(int i=0;i< arr1.length;i++){System.out.println(arr1[i]+arr[i].ordinal());}//把字符串變成對應的枚舉對象TestEnum testEnum= TestEnum.valueOf("RED");System.out.println(testEnum);REDSystem.out.println(RED.compareTo(BLACK));System.out.println(BLACK.compareTo(WHITE));} }1)枚舉的構造方法默認是私有的
?2)枚舉類是不可以被繼承的(TestEnum不可被繼承)
1)既然枚舉的構造方法是私有的,那么我們是否可以通過反射來獲取枚舉對象的實例呢?
public enum TestEnum{RED("hello",1),BLACK("world",2),GREEN("l want",3),WHITE("kkkk",4);public String color;public int origin;private TestEnum(String color,int origin) //此時的自己構造方法默認是私有的{ //這里面會默認幫助父類進行構造,會默認super(),默認執(zhí)行這個構造方法this.color=color;this.origin=origin;}public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Class<Enum> S1= (Class<Enum>) Class.forName("TestEnum"); Constructor<Enum> constructor=S1.getDeclaredConstructor(String.class,int.class); //枚舉的構造方法是私有的,所以要把參數(shù)設置成true constructor.setAccessible(true); TestEnum testEnum= (TestEnum) constructor.newInstance("BLUE",23); //構造方法里面再寫"hhh",89;那么這時還是會報錯的System.out.println("枚舉對象是"+testEnum);} } 這段代碼時會報錯的,他的報錯的意思是沒有這樣的構造方法 但是在我們所寫的代碼中,是存在這樣的構造方法的,那怎么會沒有呢?原因是我們自己所寫的枚舉類默認是繼承于上面的一個抽象類的,而這個抽象類的構造方式是含有兩個參數(shù)的,所以在我們自己所寫的枚舉類型中,我們應該先要幫助父類進行構造
Constructor<Enum> constructor=S1.getDeclaredConstructor(String.class,int.class,String.class,int.class);
// TestEnum testEnum= (TestEnum) constructor.newInstance("BLUE",23,"bit",99)
//其實本質(zhì)上TestEnum是四個構造參數(shù),構造方法里面后面再寫"hhh",89;那么這時還是會報錯的,先幫助父類進行構造
1)在咱們的反射里面的newInstance方法里面會進行判斷,如果是枚舉類型,是不可以創(chuàng)建實例的
2)所以我們進行總結,枚舉類型是非常安全的,我們無法通過反射來進行獲取到枚舉類型的實例對象
如何設置一個線程安全的單例模式呢?
1)構造方法私有化
2)實例化的變量引用私有化
3)獲取實例的方法共有
把構造方法設置成私有的,在類里面之創(chuàng)建一個實例,并進行返回;通過公開方法來獲取到一個實例;
1)設計餓漢模式和懶漢模式,里面的字段屬性一定要是private static 防止在類外被訪問到,除了獲取實例的方法之外設置成public之外;
public class Singleton {Object object = new Object();private Singleton() {};private volatile static Singleton singleton = null;public static Singleton getInstance() {if (singleton == null) {synchronized (Object.class) {if (singleton == null) {return new Singleton();}}}return singleton;}class Singleton{private Singleton(){};private static final Singleton singleton=new Singleton();public static Singleton getInstance(){return singleton;} }2)通過靜態(tài)內(nèi)部類來實現(xiàn)一個單例模式:
class Singleton{private Singleton(){};private static class User{private static final Singleton singleton=new Singleton();}public static Singleton getInstance(){return User.singleton;}} } class TestEnum{public static void main(String[] args) {Singleton singleton=Singleton.getInstance();Singleton singleton1=Singleton.getInstance();System.out.println(singleton1==singleton);} }3)通過枚舉來實現(xiàn)一個單例模式:使用枚舉實現(xiàn)單例模式利用了枚舉的特性
public enum TestEnum{RED;public static TestEnum getInstance(){return RED;}public static void main(String[] args) {TestEnum testEnum1=TestEnum.getInstance();TestEnum testEnum=TestEnum.getInstance();System.out.println(testEnum==testEnum1);} }總結
以上是生活随笔為你收集整理的Java中的反射和枚举的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Mybatis中的多对一、一对一、一对多
- 下一篇: 社会综合治理智慧综治管理系统平台Java