黑马程序员_JAVA_枚举和反射总结

------- android培训java培训、期待与您交流! ----------




枚举的介绍

枚举:

1.      为什么要有枚举

问题:要定义星期几或者性别的变量,该怎么定义呢?假设1-7分别表示星期一到星期日,单有人可能会写成int weekday=0;

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

枚举的基本应用

用普通类模拟枚举的实现原理

package com.itcast.day1;

 

public abstract class WeekDay

{

   private WeekDay()

   {

           

   }

   public finalstatic WeekDay SUN=newWeekDay()

   {

                   @Override

                   public WeekDay nextDay()

                   {

                            return MON;

                   }

   };

   public finalstatic WeekDay MON=newWeekDay()

   {

            @Override

                   public WeekDay nextDay()

                   {

                            return SUN;

                   }

   };

  

   public abstractWeekDay nextDay();

   {

           

   }

  

/*   public WeekDay nextDay()

   {

           if(this==SUN)

                      return MON;

           else

           {

                    return SUN;

           }

   }*/

 

         @Override

         public String toString()

         {

                  returnthis==SUN?"SUN":"MON";

         }

           

}

 


 

package com.itcast.day1;

 

public class EnumTest

{

    public staticvoid main(String[] args)

         {

                   WeekDayweekDay=WeekDay.MON;

                   System.out.println(weekDay.nextDay());//SUN

         }

}


java的枚举的基本应用

public class EnumTest

{

    public static void main(String[] args)

         {

                   WeekDay1 weekDay=WeekDay1.MON;

                   System.out.println(weekDay.nextDay());//SUN

                  

                   WeekDay weekDay2=WeekDay.FRI;//自动将枚举转换成string

                   System.out.println(weekDay2);//FRI

                   System.out.println(weekDay2.name());//FRI

                   System.out.println(weekDay2.ordinal());//排行 第5

                   System.out.println(WeekDay.valueOf("SUN"));//将字符串SUN转换成对象

                   System.out.println(WeekDay.values().length);//得到这个枚举数组的长度 76

         }

    //定义枚举

    public enum WeekDay

    {

             SUN,MON,TUE,WED,THI,FRI,SAT;

    }

}


实现带有构造方法的枚举

枚举也是一个类

package com.itcast.day1;

 

public class EnumTest

{

    public staticvoid main(String[] args)

         {

                   WeekDay1weekDay=WeekDay1.MON;

                   System.out.println(weekDay.nextDay());//SUN

                  

                   WeekDayweekDay2=WeekDay.FRI;//自动将枚举转换成string

                   System.out.println(weekDay2);//FRI

                   System.out.println(weekDay2.name());//FRI

                   System.out.println(weekDay2.ordinal());//排行 第5

                   System.out.println(WeekDay.valueOf("SUN"));//将字符串SUN转换成对象

                   System.out.println(WeekDay.values().length);//得到这个枚举数组的长度 76

         }

    //定义枚举

    public enumWeekDay

    {

      //        SUN,MON,TUE,WED,THI,FRI,SAT;//元素列表必须定义在最前面

             SUN(1),MON,TUE,WED,THI,FRI,SAT;//SUN(1) 加参数列表 调用有参数的构造参数

             //MON() 表示调用默认的构造方法

             //构造方法必须定义在元素列表后面

             privateWeekDay()

                   {

                            System.out.println("first");

                   }

             privateWeekDay(int day)

                   {

                       System.out.println("secod");

                   }

    }

}

 


实现带有抽象方法的枚举 

枚举只有一个成员时,就可以作为一种单例的实现方式

 

package com.itcast.day1;

 

import java.util.Date;

 

public class EnumTest

{

    public staticvoid main(String[] args)

         {

                   WeekDay1weekDay=WeekDay1.MON;

                   System.out.println(weekDay.nextDay());//SUN

                  

                   WeekDayweekDay2=WeekDay.FRI;//自动将枚举转换成string

                   System.out.println(weekDay2);//FRI

                   System.out.println(weekDay2.name());//FRI

                   System.out.println(weekDay2.ordinal());//排行 第5

                   System.out.println(WeekDay.valueOf("SUN"));//将字符串SUN转换成对象

                   System.out.println(WeekDay.values().length);//得到这个枚举数组的长度 76

        

          

         }

    //定义枚举

    public enumWeekDay

    {

      //        SUN,MON,TUE,WED,THI,FRI,SAT;//元素列表必须定义在最前面

             SUN(1),MON,TUE,WED,THI,FRI,SAT;//SUN(1) 加参数列表 调用有参数的构造参数

             //MON() 表示调用默认的构造方法

             //构造方法必须定义在元素列表后面

             privateWeekDay()

                   {

                            System.out.println("first");

                   }

             privateWeekDay(int day)

                   {

                       System.out.println("secod");

                   }

    }


    //交通灯,带上抽象方法的枚举

   

透彻分析反射的基础_Class

 

反射的基石—> Class

1.      java程序中的各个JAVA类属于同一事物,描述这类事物到的JAVA类名就是Class

2.      对比提问:众多的人用什么类表示?众多的JAVA类用什么表示?

-> Person

JAVA->Class

3.      对比提问:Person类代表人,它的实例对象就是张三,李四这样一个个具体的人,Class代表Java类,它的各个实例对象又分别是什么呢?

1.      对应各个类在内存中的字节码。例如Person类的字节码,ArrayList类的字节码,等等

2.      一个类被加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类字节码是不同的,所以他们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来

如何得到各个字节码对应的实例对象(Class类型)

1.      类名.class,例如,System.class

2.      对象.getClass(),例如,new Date().getClass();

3.      Class.foName(“类名”);,例如,Class.forName(“java.util.Date”);

 

9个预定义Class实例对象:

1.      查看Class.isPrimlative方法的帮助

2.      Int.claas==Integer.class fales

 

package com.itcast.day1;

 

public class ReflectTest

{

    public staticvoid main(String[] args) throws Exception

         {

                   Stringstr1="abc1";

                   Classclsl=str1.getClass();

                   Classcls2=String.class;

                   Classcls3=Class.forName("java.lang.String");

                  

                   System.out.println(clsl==cls2);//true

                   System.out.println(clsl==cls3);//true

                   System.out.println(clsl.isPrimitive());//false不是基本类型

                   System.out.println(int.class==Integer.class);//false

                   System.out.println(int.class==Integer.TYPE);//true

                   System.out.println(int[].class.isArray());//true

                   //数组类型的class实例对象用class.isArray()

                   //总之,只要是在源程序出现的类型都有各自的的Class实例对象,如int[],void

         }

}

 

 public enumTrafficLamp

    {

             //相等于new子类的实例对象,并且调用父类的有参数的构造方法

             RED(30){

                      

                            @Override

                            public TrafficLamp nextLamp()

                            {

                               //红灯以后返回绿灯

                                     return GREEN;

                            }

                      

             },

             GREEN(45){

 

                            @Override

                            public TrafficLamp nextLamp()

                            {

                                     //绿灯以后黄

                                     return YELLOW;

                            }

                      

             },

             YELLOW(5){

 

                            @Override

                            public TrafficLamp nextLamp()

                            {

                                     //黄灯以后红灯

                                     return RED;

                            }

                      

             };

             publicabstract TrafficLamp nextLamp();

             privateint time;//每个灯都拥有自己的时间

             privateTrafficLamp(int time)

             {

                       this.time=time;

             }

    }

}

 

理解反射的概念

 

反射

1.      反射就是把Java类中的各种成分映射成相应的的java类。例如,一个java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等信息也用一个个的Jvaa类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类,表示java类的Class类显然要提供一系列的方法,来获取其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应的类的实例对象来表示,他们的Field,Method,Contructor,Package等等

2.      一个类中的每个成员都可以用到相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到这些实例对象后,得到这些实例后怎么用?

 

构造方法的反射应用

Constructor

1.      Constructor类代表某个类中的一个构造方法

2.      得到某个类的所有构造方法

例子:Constructor construtors[]=Class.forName(“java.lang.String”).getConstrutors();

3.      得到某一个构造方法:

例子: Constructors constructors=Class.forName(“java.lang.String”).getContstructor(StringBuffer.class);

    //获得方法是要用到的类型

4.      创建实例对象

1.      通常方式:String str=new String(new StringBufferf(“abc”));

2.      反射方式:String str=(Strtring)constructor.newInstance(new StringBuffer(“abc”));

     //调用方法时要用到上面相同的类型的实例对象

5.      Class.newInstance()方法

例子:String obj=(String)Classs.forName(“java.lang.String”).newInstance();

该方法内部先得到默认的构造方法,然后该构造方法创建实例对象

该方法内部的具体代码是怎样写的呢?用到了缓冲机制来保存默认的构造方法的实例对象

public staticvoid main(String[] args) throws Exception

         {

                   String.class.getConstructor(StringBuffer.class);//值接受一个参数的的构造方法

              String str2=new String(newStringBuffer("jj"));

             

             // Constructorconstructor=String.class.getConstructor(StringBuffer.class)

                           Constructorconstructor=Class.forName("java.lang.String").getConstructor(StringBuffer.class);

              String str3=(String)constructor.newInstance(newStringBuffer("aaa"));

         }


成员变量的反射

 Field

1.      Field类代表某个类中的一个成员变量

2.      演示用eclipse自动生成Java类的构造方法

3.      问题:得到的Field都系是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,而该类的实例对象有多个,如果是与对象关联,哪关联的是哪个对象呢?所以字段fieldX代表的是X的定义,而不是具体的X变量

实例代码:

 

 

public class ReflectPoint

{

    private intx;

    public inty;

         public ReflectPoint(int x, int y)

         {

                   super();

                   this.x = x;

                   this.y = y;

         }

   

}

 

 

package com.itcast.day1;

 

import java.lang.reflect.*;

 

public class ReflectTest

{

    public staticvoid main(String[] args) throws Exception

         {

                  

              ReflectPoint fp=new ReflectPoint(3,5);

              Field fieldY=fp.getClass().getField("y");//代表变量,不代表值

              System.out.println(fieldY);

              System.out.println(fieldY.get(fp));//从那个对象上取出y

             

//对于私有属性:设置可见----->设置可以访问

              FieldfieldX=fp.getClass().getDeclaredField("x");//面对私有的变量,看不见,就用声明的字段方法获取

              fieldX.setAccessible(true);//暴力反射,不管对方同意不?设置可以可以访问

              System.out.println(fieldX.get(fp));

             

         }

}


成员变量反射的综合案例

 

作业:将任意一个对象中的所有String类型的成员变量所对应的字符串内容的”b“改成”a”;

package com.itcast.day1;

 

public class ReflectPoint

{

    private intx;

    public inty;

    public String str1="ball";

    public String str2="basketball";

    public String str3="itcast";

         public ReflectPoint(int x, int y)

         {

                   super();

                   this.x = x;

                   this.y = y;

         }

         @Override

         public String toString()

         {

                   return str1+":"+str2+":"+str3;

         }

   

}

 


 

package com.itcast.day1;

 

import java.io.File;

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

 

public class ReflectTest

{

    public staticvoid main(String[] args) throws Exception

         {

              changeStringValue(fp);

              System.out.println(fp);//aall:aasketaall:itcast

         }

 

         private staticvoid changeStringValue(Object obj) throws Exception

         {

                   Field[]fields=obj.getClass().getFields();

                   for(Field field:fields)

                   {

                            if(field.getType()==String.class)

                            {

                                     StringoldValue=(String) field.get(obj);

                                     StringnewValue=oldValue.replace('b','a');//替换

                                     field.set(obj,newValue);//设置对象上的那个值

                            }

                   }

                  

         }

   

}


 

成员方法的反射

Method

1.       Method类代表某个类中的一个成员方法

2.      得到类中的某一个方法:

例子:

Method charAt=Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);

3.      调用方法:

通常方式:System.out.println(str.charAt(1));

反射方式:System.out.println(charAt.invoke(str,1));

     如果传递给Method对象的invoke()方法的一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法!

 

4.      jdk1.4jdk1.5invoke方法的区别

jdk1.5public Object invoke(Object obj,Object…args)

Jdk1.4:   publicObject invoke(Object obj,Object[] args),即按照jdk1.4的语法

需要将与各数组作为参数传递给invoke方法时,数组中的每个元素分别对应被

public static void main(String[] args) throws Exception

         {

                   Stringstr1="abc1";

              //调用str1.charAt(1);

              Method methodCharAt=String.class.getMethod("charAt",int.class);

              System.out.println(methodCharAt.invoke(str1,1));//调用charAt方法,此得到b

              //methodCharAt.invoke(null,1)  调用静态方法,对象为null

              System.out.println(methodCharAt.invoke(str1,new Integer[]{2}));//jdk.1.4调用方式

         }

 


对接收数组参数的成员方法进行反射

用反射的方式执行某个类中的main方法

1.      目标:

写一个程序,这个程序能够根据用户提供的类名,去执行类中的main方法

普通方式调用完后,

2.      问题

启动java程序的main方法参数是一个字符串数组,即public static void main(String[] args),通过反射的方式来刁永红这个main方法时,如果和为invoke方法传递参数呢?按jdk1.5的语法,整个数组是一个参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,当把一个字符串作为参数传递给invoke方法时,javac会到底按照那种语法进行执行呢?jdk1.5版本肯定要兼容jdk1.4的语法,会按照jdk1.4的语法进行处理,即把数组打散成为若干个单独的参数。所以,在给main方法传递参数时,不能使用代码mianMethod.invoke(null,new String[]{“xxx”}),javac只能把它的那个在jdk1.4的语法进行理解,而不把它当做jdk1.5的预付解释,因此会出现参数类型不对的问题

 

5.      解决办法:

mainMethod.invoke(null,new Object[]{new String{“xxx”}});

mainMethod.invoke(null,(Object)new String[]{“xxx”});,编译器会做特殊处理,编译时不会把参数当做数组看待,也就不会进数组打散成若干参数了

 

package com.itcast.day1;

 

import java.io.File;

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

 

public class ReflectTest

{

   public static void main(String[] args) throws Exception

         {

             //TestArguments.main(new String[]{"acb","hhf","jdj"});

              //用反射的方式调用

                 

              String startingClassName=args[0];

              MethodmainMethod=Class.forName(startingClassName).getMethod("main",String[].class);

              //现将字符串打包成一个Object对象数组的第一个对象

              mainMethod.invoke(null, new Object[]{newString[]{"acb","hhf","jdj"}});

             

              //或者

            // mainMethod.invoke(null,(Object)newString[]{"acb","hhf","jdj"});

        

         }

 

         privatestatic void changeStringValue(Object obj) throws Exception

         {

                   Field[]fields=obj.getClass().getFields();

                   for(Fieldfield:fields)

                   {

                            if(field.getType()==String.class)

                            {

                                     StringoldValue=(String) field.get(obj);

                                     StringnewValue=oldValue.replace('b','a');//替换

                                     field.set(obj,newValue);//设置对象上的那个值

                            }

                   }

                  

         }

   

}

class TestArguments

{

         publicstatic void main(String[] args)

         {

                   for(Stringarg:args)

                   {

                            System.out.println(arg);

                   }

         }

}


数组与Object的关系及其反射类型

 

数组(具有相同的元素类型,和相同的纬度)的字节码是同一个对象

  

int[] a1=newint[]{1,2,3};

              int[]a2=new int[4];

              int[][]a3=new int[2][3];

              String[] a4=newString[]{"a","b","c"};

              System.out.println(a1.getClass()==a2.getClass());//true

             //System.out.println(a1.getClass()==a4.getClass());//报错

             

              System.out.println(a1.getClass().getName());//[I   表示数组 整数

              System.out.println(a1.getClass().getSuperclass());//class java.lang.Object

             System.out.println(a1.getClass().getSuperclass().getName());

/*

父类名    java.lang.Object

*/      

             

              Object obj1=a1;

              Object obj2=a4;

            //  Object[] obj3=a1;不能转换

              Object[] obj4=a3;

              Object[] obj5=a4;

             

              System.out.println(a1);//[I@43ef9157

              System.out.println(Arrays.asList(a1));//[[I@331f2ee1]

              System.out.println(Arrays.asList(a4));//[a, b, c]

 

数组的反射应用

 

数组的反射

1.      具有相同的纬度和元素类型的数组属于同一个类型,即具有相同的Class实例对象

2.      代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class

3.      基本类型的一维数组可以被当做Objetc类型使用,不能当做Objetc[] 类型使用;非基本类型的一维数组,即可以当做Object类型的使用,又可以当做Object[]类型使用

4.      Arrays.asList()方法处理int[]String[]时的差异

5.      Array工具类用于完成对数组的反射操作

思考题:怎么得到数组的元素类型?没办法

 

 public staticvoid main(String[] args) throws Exception

         {

String[] aa=new String[]{"a","b","c"};

              Object obj=aa;

              printObject(obj);

              printObject("jjd");

         }

 

         private staticvoid printObject(Object obj)

         {

                   Classclasszz=obj.getClass();

                   if(classzz.isArray())//是数组

                   {

                            int len=Array.getLength(obj);//得到长度

                            for(inti=0;i<len;i++)

                            {

                                     System.out.println(Array.get(classzz, i));

                            }

                   }

                   else

                   {

                            System.out.println(obj);

                   }

         }

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值