黑马程序员- 枚举和反射

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

 

 
l 枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。
l枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后要有分号与其他成员分隔。把枚举中的成员方法或变量等放在枚举元素的前面,编译器报告错误。
l带构造方法的枚举
Ø构造方法必须定义成私有的
Ø如果有多个构造方法,该如何选择哪个构造方法?
Ø枚举元素MONMON()的效果一样,都是调用默认的构造方法。
l带方法的枚举
Ø定义枚举TrafficLamp
Ø实现普通的next方法
Ø实现抽象的next方法:每个元素分别是由枚举类的子类来生成的实例对象,这些子类采用类似内部类的方式进行定义。
Ø增加上表示时间的构造方法
l枚举只有一个成员时,就可以作为一种单例的实现方式。
<!--[if ppt]--> l<!--[endif]-->
    没有enum之前其实也可以用普通的类实现枚举,但比较麻烦和不好理解,比如要对一周的周一到周日做个类的描述,可以写一下代码:
package cn.itcast.day1;  
  
public abstract class WeekDay1 {  
    private WeekDay1() {  
    }  
  
    public final static WeekDay1 SUN = new WeekDay1() {  
        public WeekDay1 nextDay() {  
            return MON;  
        }  
    };  
    public final static WeekDay1 MON = new WeekDay1() {  
        public WeekDay1 nextDay() {  
            return SUN;  
        }  
    };  
  
    public abstract WeekDay1 nextDay();  
  
    public String toString() {  
        if (this == SUN) {  
            return "SUN";  
        } else {  
            return "MON";  
        }  
    }  
}  
 
 
    这里实现了本类的实例对象的下一个对象是谁,只用了MON,SUN两个值来举例说明,如果是多个值则会变得更加复杂,如果用枚举类型来设计的话会变得异常简单。
public enum WeekDay {  
    SUN,MON,TUE,WED,THI,FRI,SAT;  
    private WeekDay(){  
    }  
    private WeekDay(int day){}  
} 
 
 
  枚举有点类似于类,可以把它当成一个特殊的类,它里面封装了一些方便,好用的方法对枚举类型的数据操作变得简单了很多。注意:枚举里面的构造方法必须是private 也就是说他不能被直接创建对象。
    枚举里面的成员用逗号隔开,最后一个成员用分号结束。我的理解是里面的成员类似于已经创建好的枚举类的对象,可以通过枚举名的一些方法获取,比如:WeekDay.values()[2],获取成员数组的第二个成员,WeekDay.valueOf("MON") 通过字符串来获取某个成员。也可以通过枚举名获得对象,但不是通过new方法,比如说:WeekDay weekDay=WeekDay.TUE 就获得了一个对象。System.out.println(weekDay)是打印这个枚举对象,System.out.println(weekDay.toString())同上。
    下面写一个交通灯的代码
public enum TrafficLamp {  
    RED(30) {  
        public TrafficLamp nextLamp() {  
            return GREEN;  
        }  
    },  
    GREEN(30) {  
        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;  
    }  
}  
 
虽然没有类,但枚举成员类似于类中new TrafficLamp()这样的方式来创造对象,所以里面是可以根据构造方法的参数列表情况传入实际参数的,由于方法public abstract TrafficLamp nextLamp() 是一个抽象的方法所以必须实现在创造成员时实现抽象方法。
    
    首先要了解一个叫Class的类,这是特殊的类,因为它创建的对象是一个类(可以理解为字节码),也就是说把类这种事物抽象归纳一下也可以有一些共同的方法和属性的,所以有了一个Class类。一般有三种方式来获取Class对象:1.类名.class,比如说String是一个类,可以通过String.class获得一个对象,它是一段字节码。2.对象.getClass(),比如变量str是String类型的对象,通过str.getClass()获得String类的字节码。3.Class类的静态方法来获取,Class.forName("java.lang.String")来获取类String的字节码。
    通过获取的类的字节码可以有一些方法供我们调用,下面列举一些常用的方法:
     isPrimitive() 是否属于基本类型,如果是那八种基本数据类型则返回true。
     getConstructor(Class<?>... parameterTypes) 返回该类的构造方法。里面是参数列表。举例如下:Constructor<String> c=String.class.getConstructor(StringBuffer.class);
String s= (String)c.newInstance(new StringBuffer("123"));
System.out.println(s.charAt(2));
 
 
 java中反射技术的应用还表现在,当编写主程序时,外部程序还没有确定,那么这时就可以先编写好主程序,利用反射技术,把未知的class加入,当运行时再载入。比如,当运行一个主函数时,我想把想要加载的对象也添加运行,怎么办?这时就要用到反射技术。
需求:当运行一段main主函数时,在程序中加载运行另一个类的主函数。
分析:因为写main主函数时尚且不知道要运行的另一个类的名称,所以只能动态的写入,在运行配置项中给出要 加载类的名称,这样先打好框架,可以提高代码的复用性。
 
package cn.itcast.day1;  
  
import java.lang.reflect.*;  
  
public class ReflectTest3 {  
  
    public static void main(String[] args) throws Exception {  
        String startingClassName = args[0];  
        Method methodMain = Class.forName(startingClassName).getMethod("main",  
                String[].class);  
        methodMain.invoke(null,  
                (Object) new String[] { "haha", "hehe", "xixi" });  
    }  
  
}  
  
class ReflectArguments {  
    public static void main(String[] args) {  
        for (String arg : args) {  
            System.out.println(arg);  
        }  
    }  
}  
 
 
 由于要加载的类写进了配置项,所以通过String startingClassName=args[0]语句来取得类的名称,Class.forName是类Class的静态方法,用来得到类的字节码对象,通过类的字节码对象的方法getMethod得到其中的"main"方法。getMethod方法中的第一个参数是方法名,后面一个参数是方法列表。 注意,由于类中的方法是多态的所以getMethod第二个参数是不确定的。
    这样就获得了Method类的对象methodMain,调用methodMain的方法invoke来执行其中的main方法。 注意,如果该方法是静态的,invoke方法的第一个参数是null,表示没有对象,直接用类名调用的意思。第二个参数是执行的方法实际要传入的参数。
 
 
 

 在实际开发中还有另一种情况,就是要从配置文件中提取数据来参与到代码运算中来,先看一段代码,然后再来分析:

package cn.itcast.day1;  
  
import java.util.*;  
import java.io.*;  
  
public class ReflectTest2 {  
  
    public static void main(String[] args) throws Exception {  
        InputStream ips = ReflectTest2.class  
                .getResourceAsStream("config.properties");  
        Properties props = new Properties();  
        props.load(ips);  
        ips.close();  
        String className = props.getProperty("className");  
        Collection collections = (Collection) Class.forName(className)  
                .newInstance();  
        ReflectPoint rp1 = new ReflectPoint(3, 5);  
        ReflectPoint rp2 = new ReflectPoint(3, 3);  
        ReflectPoint rp3 = new ReflectPoint(3, 8);  
        ReflectPoint rp4 = new ReflectPoint(3, 5);  
        collections.add(rp1);  
        collections.add(rp2);  
        collections.add(rp3);  
        collections.add(rp4);  
        collections.add(rp1);  
        System.out.println(collections.size());  
    }  
  
}  
  
public class ReflectPoint {  
  
    private int x;  
    public int y;  
    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;  
    }  
  
    public String toString() {  
        return str1 + "::" + str2 + "::" + str3;  
    }  
  
    @Override  
    public int hashCode() {  
        final int prime = 31;  
        int result = 1;  
        result = prime * result + x;  
        result = prime * result + y;  
        return result;  
    }  
  
    @Override  
    public boolean equals(Object obj) {  
        if (this == obj)  
            return true;  
        if (obj == null)  
            return false;  
        if (getClass() != obj.getClass())  
            return false;  
        ReflectPoint other = (ReflectPoint) obj;  
        if (x != other.x)  
            return false;  
        if (y != other.y)  
            return false;  
        return true;  
    }  
}  

 

 

需求是从配置文件中提取信息,是用哪种类型的Collection来存取对象,假设我的配置文件config.properties已经存放了一个键值对className=java.util.ArrayList,那么通过类加载器ReflectTest2.class.getResourceAsStream("config.properties")获得文件config.properties的文件流对象。注意,因为类加载器是寻找它本目录下的文件,所以如果只要把文件config.properties放在bin目录下的本包中的class文件一起,就可以用相对路径"config.properties"来表示,如果放在其他目录,要用绝对路径表示。然后用Properties类的对象来载入文件流,String className= props.getProperty("className") 这个语句可以获得className这个键的值,也就是字符串"java.util.ArrayList",所以再通过语句Collection collections=(Collection)Class.forName(className).newInstance() 就可以得到一个ArrayList的集合对象。由于集合可以添加相同元素,所以打印结果为5。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值