枚举、反射和内省总结

来源:互联网 发布:淘客助手mac版 编辑:程序博客网 时间:2024/05/29 12:41

主要内容:

1. 枚举知识总结

2. 枚举应用

3. 反射知识总结

4. 反射应用

5. 泛型知识总结

6. 内省总结

枚举知识总结:

枚举的作用:
枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。

枚举特点:
1)枚举就相当于一个类,其中的每个枚举元素都是该类的一个实例对象,也可以定义构造方法、成员变量、普通方法和抽象方法。
2)枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后要有分号与其他成员分隔。把枚举中的成员方法或变量等放在枚举元素的前面,编译器报告错误。
3)枚举只有一个成员时,就可以作为一种单例的实现方式。
4)每个枚举元素都有一个序数(它在枚举声明中的位置,其中初始常量序数为零)

枚举的构造函数:
1)构造方法必须定义成私有的。
2)枚举元素MON和MON()的效果一样,都是调用默认的构造方法。
3)枚举可以有带参数的构造方法,枚举元素可以带参数初始化。
   注意:枚举元素实例化不用new,因为每个枚举元素都是该类的一个实例对象,直接引用枚举类中的枚举元素,第一次引用枚举元素,所有的元素都将初始化,只被初始化一次,之后的引用都不再调用构造函数。

枚举应用:

应用一:
需求:定义一个Weekday的枚举。演示枚举类的values,valueOf,name,toString,ordinal等方法
应用二:
需求:定义枚举TrafficLamp
            实现普通的next方法
            实现抽象的next方法:每个元素分别是由枚举类的子类来生成的实例对象,这些子类采用类似内部类的方式进行定义。
            增加上表示时间的构造方法
代码示例:
public class EnumTest {/** *  * @param args */public static void main(String[] args) {// TODO Auto-generated method stub//枚举元素不用new,直接引用其元素WeekDay week1 = WeekDay.FRI;WeekDay week2 = WeekDay.FRI;System.out.println(WeekDay.THU);System.out.println(week1.equals(week2));System.out.println(week1.toString());//获取枚举常量序数System.out.println(week1.ordinal());System.out.println(TrafficLamp.RED.nextLamp());}//枚举应用一:public enum WeekDay{//调用有参数构造方法直接在元素后传参SUN,MON,TUE,WED,THU(1),FRI(2),SAT;private WeekDay(){System.out.println("first");}private WeekDay(int i){System.out.println("second");}}//枚举应用二public enum TrafficLamp{//子类采用类似内部类的方式进行定义RED(30){public TrafficLamp nextLamp(){return GREEN;}},GREEN(45){public TrafficLamp nextLamp(){return YELLOW;}},YELLOW(5){public TrafficLamp nextLamp(){return RED;}};//抽象方法public abstract TrafficLamp nextLamp();private int time;private TrafficLamp(int time){this.time = time;}public int getTime() {return time;}public void setTime(int time) {this.time = time;}}}

反射知识总结:

反射,就是把Java类中的各种成分映射成相应的java类。例如,一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示。
表示java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示。
反射知识中涉及到的类:
Class类、Constructor类、Field类、Method类。

Class类:
 Class类是反射的基石。
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。
枚举是一种类,注释是一种接口。
每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象。
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。
常用方法:
1.  获得各个字节码对应的实例对象(Class类对象)
        类名.class,例如,System.class
        对象.getClass(),例如,new Date().getClass()
        Class.forName("类名"),例如,Class.forName("java.util.Date");

2.  获得Classo类对象某个方法的Method对象
         Method getMethod(String name, Class<?>... parameterTypes);

3. 获得Class类对象所表示的实体(类、接口、数组类、基本类型或 void)名称。
        String getName() ; 

4. 获得Class 对象所表示的类的指定公共构造方法
        Constructor<T> getConstructor(Class<?>... parameterTypes);

5. Class.newInstance()方法:
        例子:String obj = (String)Class.forName("java.lang.String").newInstance();
        创建此 Class 对象所表示的类的一个新实例,默认调用的用无参构造函数。这时候适合调用其静态方法。
        该方法内部的具体代码是怎样写的呢?用到了缓存机制来保存默认构造方法的实例对象。

6. 获得该类的类加载器
        ClassLoader getClassLoader();
7. 强制转换该 Class 对象,以表示指定的 class 对象所表示的类的一个子类。
         Class<? extends U> asSubclass(Class<U> clazz);
8.  获取此类的包
         Package getPackage()
代码示例:
import java.lang.reflect.Array;import java.lang.reflect.Constructor;import java.lang.reflect.Field;public class ReflectTest {/** *  * @param args */public static void main(String[] args)throws Exception{String str = "abc";Class cls0 = str.getClass();Class cls1 = String.class;Class cls2 = Class.forName("java.lang.String");//打印Class类对象的toString形式System.out.println(cls0);System.out.println(cls0==cls1);System.out.println(cls2==cls1);//获得cls0所表示类的名称String strName = cls0.getName();System.out.println(strName);//用cls0创建一个新的String对象,String str1 = (String)cls0.newInstance();System.out.println(str1.isEmpty());}

Constructor类:

Constructor 提供关于类的单个构造方法的信息以及对它的访问权限。
Constructor 允许在将实参与带有底层构造方法的形参的 newInstance() 匹配时进行扩展转换,但是如果发生收缩转换,则抛出 IllegalArgumentException。 

1. 得到某个类所有的构造方法:
        例子:Constructor [] constructors= Class.forName("java.lang.String").getConstructors();
2. 得到某一个构造方法:
        例子: Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);
3. 创建实例对象:
        通常方式:String str = new String(new StringBuffer("abc"));
        反射方式: String str = (String)constructor.newInstance(new StringBuffer("abc"));
4. Class.newInstance()方法:
        例子:String obj = (String)Class.forName("java.lang.String").newInstance();
代码示例:

import java.lang.reflect.Array;import java.lang.reflect.Constructor;import java.lang.reflect.Field;public class ReflectTest {/** *  * @param args */public static void main(String[] args)throws Exception{String str = "abc";Class cls0 = Class.forName("java.lang.String");System.out.println(cls0);//用cls0创建一个新有String对象,用有参数构造函数Constructor ctor0 = cls0.getDeclaredConstructor(String.class);//值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。//值为 false 则指示反射的对象应该实施 Java 语言访问检查。//ctor0.setAccessible(true);String str2 = (String)ctor0.newInstance("成了?");System.out.println(str2);}

Field类:
Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限,代表某个类中的一个成员变量。反射的字段可能是一个类(静态)字段或实例字段。
Array 允许在执行 get 或 set 访问操作期间进行扩展转换,但如果将发生收缩转换,则抛出一个 IllegalArgumentException。
常用方法:

1. 获得此 Class 对象所表示的类或接口的指定公共成员字段

        Field getField(String s);   

2. 获得此 Class 对象所表示的类或接口的指定已声明字段

        Field getDeclaredField(String s);   

3. 暴力访问,取消访问检查,可以访问私有字段
        setAccessible(ture);

4. 获得 Field 对象所表示字段的声明类型的Class对象

        Class<?> getType();

5. 获得指定对象上此 Field 表示的字段的值

         Object get(Object obj) ; 

代码示例:

public class ReflectTest {/** *  * @param args */public static void main(String[] args)throws Exception{ReflectPoint obj = new ReflectPoint(2,5);System.out.println(obj);Field[] fields = obj.getClass().getFields();for(Field field : fields){//用String字节码来识别String字段,用"=="比,很巧妙if(field.getType() == String.class){String oldValue = (String)field.get(obj);String newValue = oldValue.replace('b', 'a');field.set(obj, newValue);}}System.out.println(obj);}

Method类:

Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。
Method 允许在匹配要调用的实参与底层方法的形参时进行扩展转换;但如果要进行收缩转换,则会抛出 IllegalArgumentException。
1. 得到类中的某一个方法:
        例子: Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
2. 调用方法:
        通常方式:System.out.println(str.charAt(1));
        反射方式: System.out.println(charAt.invoke(str, 1));
3. 如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?

        说明该Method对象对应的是一个静态方法!

4. jdk1.4和jdk1.5的invoke方法的区别:
        Jdk1.5:public Object invoke(Object obj,Object... args)
        Jdk1.4:public Object invoke(Object obj,Object[] args),

        即按jdk1.4的语法,需要将一个数组作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,

        所以,调用charAt方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, new Object[]{1})形式。

5. 在eclipse运行当前类的main方法,要向main方法中传递参数,该怎么做?

      右键点击编辑区,选Run As菜单下Run Configurations,在参数栏里(Arguments)填上要传递的参数,保存即可。
代码示例一:调用其他类中main方法

public class ReflectTest {/** *  * @param args */public static void main(String[] args)throws Exception{/** * 需求:写一个程序能调用别人的main()方法 *///常规静态调用main方法MethodDemo.main(new String[]{"aaa","bbb","1324"});//使用反射调用main方法String startingClassName = args[0];Method  mainMethod = Class.forName(startingClassName).getMethod("main", String[].class);//第一个参数为空,表示该Method对象对应的是一个静态方法mainMethod.invoke(null, (Object)new String[]{"aaa","bbb","1324"});}}
代码示例二:数组反射

import java.lang.reflect.Array;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.util.Arrays;public class ReflectTest {/** *  * @param args */public static void main(String[] args)throws Exception{//数组的反射测试int[] ar = {1,24,4};int[][] ar2 = new int[2][3];String[] str = {"heihei","hehe","haha"};char[] ch = {'a','b','c'};//所有数组的父类都是java.lang.ObjectSystem.out.println(ar.getClass().getName());System.out.println(ar.getClass().getSuperclass().getName());System.out.println(str.getClass().getSuperclass().getName()); System.out.println(str.getClass().getName()); System.out.println(ch.getClass().getSuperclass().getName());/*//因此他们都可以和Object互转,以对象为单位,基本类型不能和对象互转,//数组本身就是一个对象Object obj1 = ar;//Object[] obj2 = ar[]; //不能这样,基本类型不能和对象互转。Object obj5= ch;Object[] obj3 = ar2; Object obj4 = str;*/System.out.println(Arrays.asList(ar));System.out.println(Arrays.asList(ch));printObject(ar);printObject(str);printObject(ch);}//利用反射方法来打印数组public static void printObject(Object obj){Class cla = obj.getClass();if(cla.isArray()){int len = Array.getLength(obj);for(int i=0; i<len; i++){System.out.println(Array.get(obj, i));}}}}

内省:Introspector

内省的出现有利于了对类对象属性的操作,减少了代码的数量。
与之相关的类是:JavaBean.
JavaBean是一种特殊的Java类,主要用于传递数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则:
去掉set前缀,剩余部分就是属性名,如果剩余部分的第二个字母是小写的,则把剩余部分的首字母改成小的。
setId()的属性名——>id
isLast()的属性名——>last
setCPU的属性名是什么?——>CPU
getUPS的属性名是什么?——>UPS
总之,一个类被当作javaBean使用时,JavaBean的属性是根据方法名推断出来的,它根本看不到java类内部的成员变量。

JavaBean的优势:
  1. 在Java EE开发中,经常要使用到JavaBean。很多环境就要求按JavaBean方式进行操作,别人都这么用和要求这么做,那你就没什么挑选的余地!
  2. JDK中提供了对JavaBean进行操作的一些API,这套API就称为内省。如果要你自己去通过getX方法来访问私有的x,怎么做,有一定难度吧?用内省这套api操作JavaBean比用普通类的方式更方便。
内省的综合案例:

package cn.itcast.day1;import java.beans.IntrospectionException;import java.beans.PropertyDescriptor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class IntrospectorTestDemo {/** * @param args */public static void main(String[] args)throws Exception{// TODO Auto-generated method stubReflectPoint refp=new ReflectPoint(2,3);String propertyName="x";//"x"-->"X"-->"getX"-->MethodGetX-->//用内省的方式//获取并getX方法Object getX = getProperty(refp,propertyName);System.out.println(getX);Object value=5;//获取并调用setX方法setProperty(refp,propertyName,value);Object getX1 = getProperty(refp,propertyName);System.out.println(getX1);}//获取并调用setX方法private static void setProperty(ReflectPoint refp, String propertyName,Object value) throws IntrospectionException,IllegalAccessException, InvocationTargetException {PropertyDescriptor pd=new PropertyDescriptor(propertyName,refp.getClass());//创建对象关联Method methodSetX=pd.getWriteMethod();//获取JavaBean类中的setX方法methodSetX.invoke(refp,value);//调用setX方法}//获取并getX方法private static Object getProperty(ReflectPoint refp, String propertyName)throws IntrospectionException, IllegalAccessException,InvocationTargetException {PropertyDescriptor pd=new PropertyDescriptor(propertyName,refp.getClass());//创建对象关联Method methodGetX=pd.getReadMethod();//获取JavaBean类中的getX方法Object retval=methodGetX.invoke(refp);//调用getX方法return retval;}}


0 0
原创粉丝点击