---------------------- android培训、java培训、期待与您交流! ----------------------
枚举
枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。
1.私有构造方法
2.每个元素分别用一个共有的静态成员变量表示
3.可以有若干共有方法或抽象方法
4.枚举类就是class,而且是一个不可以被继承的final类。枚举元素必须位于枚举中的最开始部分,枚举元素列表的后面有分号与其他成员分隔。(枚举值都是public static final的,也就是我们经常所定义的常量方式,因此枚举类中的枚举值最好全部大写。)
5.枚举类是class,在枚举类型中有构造器,方法和数据域。但是,枚举类的构造器有很大的不同:
构造器只是在构造枚举值的时候被调用。
构造器只能私有private,绝对不允许有public构造器。 这样可以保证外部代码无法新构造枚举类的实
例。
这也是完全符合情理的,因为我们知道枚举值是public static final的常量而已。 但枚举类的方法和数据
域可以允许外部访问。
6.所有枚举类都继承了Enum的方法。
ordinal()方法: 返回枚举值在枚举类种的顺序。这个顺序根据枚举值声明的顺序而定。
compareTo()方法: Enum实现了java.lang.Comparable接口,因此可以比较象与指定对象的顺序。Enum中的compareTo返回的是两个枚举值的顺序之差。当然,前提是两个枚举值必须属于同一个枚举类,否则会抛出ClassCastException()异常。
values()方法: 静态方法,返回一个包含全部枚举值的数组。
toString()方法: 返回枚举常量的名称。
valueOf()方法: 这个方法和toString方法是相对应的,返回带指定名称的指定枚举类型的枚举常量。
equals()方法: 比较两个枚举类对象的引用 。
7.枚举类可以在switch语句中使用。
public class TestEnum {
/*最普通的枚举*/
public enum ColorSelect {
red, green, yellow, blue;
}
/* 枚举也可以象一般的类一样添加方法和属性,你可以为它添加静态和非静态的属性或方法,这一切都象你在一般的类中做的那样. */
public enum Season {
// 枚举列表必须写在最前面,否则编译出错
winter, spring, summer, fall;
private final static String location = "Phoenix";
public static Season getBest() {
if (location.equals("Phoenix"))
return winter;
else
return summer;
}
}
/*还可以有构造方法*/
public enum Temp {
/*通过括号赋值,而且必须有带参构造器和一属性跟方法,否则编译出错
* 赋值必须是都赋值或都不赋值,不能一部分赋值一部分不赋值
* 如果不赋值则不能写构造器,赋值编译也出错*/
absoluteZero(-459), freezing(32),boiling(212), paperBurns(451);
private final int value;
public int getValue() {
return value;
}
//构造器默认也只能是private, 从而保证构造函数只能在内部使用
Temp(int value) {
this.value = value;
}
}
public static void main(String[] args) {
/*
* 枚举类型是一种类型,用于定义变量,以限制变量的赋值 赋值时通过"枚举名.值"来取得相关枚举中的值
*/
ColorSelect m = ColorSelect.blue;
switch (m) {
/*注意:枚举重写了ToString(),说以枚举变量的值是不带前缀的
*所以为blue而非ColorSelect.blue
*/
case red:
System.out.println("color is red");
break;
case green:
System.out.println("color is green");
break;
case yellow:
System.out.println("color is yellow");
break;
case blue:
System.out.println("color is blue");
break;
}
System.out.println("遍历ColorSelect中的值");
/*通过values()获得枚举值的数组*/
for (ColorSelect c : ColorSelect.values()) {
System.out.println(c);
}
System.out.println("枚举ColorSelect中的值有:"+ColorSelect.values().length+"个");
/*ordinal()返回枚举值在枚举中的索引位置,从0开始*/
System.out.println(ColorSelect.red.ordinal());//0
System.out.println(ColorSelect.green.ordinal());//1
System.out.println(ColorSelect.yellow.ordinal());//2
System.out.println(ColorSelect.blue.ordinal());//3
/*枚举默认实现了java.lang.Comparable接口*/
System.out.println(ColorSelect.red.compareTo(ColorSelect.green));
System.out.println(Season.getBest());
for(Temp t:Temp.values()){
/*通过getValue()取得相关枚举的值*/
System.out.println(t+"的值是"+t.getValue());
}
}
}
反射
1.什么是反射
反射就是通过.class文件来操作一个类, 可以调用构造函数, 执行方法, 访问成员变量.
反射可以让程序变得更加灵活, 例如: 可以通过一个字符串创建对象, 通过一个方法名调用方法, 通过变量名访问变量
以后在使用框架的时候, 我们经常会在配置文件中指定一些配置, 而框架会自动使用这些配置创建对象, 调用方法, 给变量赋值, 执行一些工作.
2.使用类名创建对象
以后的编程过程中经常会使用配置文件, 在配置文件中写一个类名, 然后程序运行时就会创建这个类的对象, 使用对象进行工作.
这里就需要根据类名灵活的创建对象.
可以使用Class.forName(String)方法传入一个类名, 获取一个Class对象(.class文件), 然后可以调用Class.newInstance()方法创建该类实例.
3.使用类中其他构造函数
Class.newInstance()方法默认调用类中无参的构造函数, 如果想调其他有参构造函数, 需要获取构造函数之后再调用.
调用Class.getConstructor(Class...)方法, 传入指定的参数类型, 就可以获取指定的构造函数.
再调用Constructor.newInstance(Object...)方法, 传入指定参数, 就可以调用该构造函数创建对象了.
4.获取Class的3种方式
Class.forName(String)
Object.getClass()
类名.class
5.使用类中的方法
Class.getMethod(String, Class...)方法可以获取该类中的可见方法, 包括Class.getDeclaredMethod(String, Class...)方法可以获取该类中定义的方法, 包括私有的以上方法都会获取到Method, 而使用Method.invoke(Object, Object...)即可调用该方法,如果方法不可见可以使用Method.setAccessible(boolean)方法设置其可见
6.使用类中的成员变量
Class.getField(String)方法可以获取该类中可见的成员变量, 包括继承的
Class.getDeclaredField(String)方法可以获取该类中定义的成员变量, 包括私有的
以上方法都会获取到Field, 而使用Filed.get(Object)方法可以获取指定对象的成员变量的值
使用Filed.set(Object, Object)方法可以设置指定对象的成员变量的值
如果成员宾利不可见可以使用Field.setAccessible(boolean)方法设置其可见
榨汁机的反射例子:
import java.io.BufferedReader;
import java.io.FileReader;
import java.lang.reflect.Method;
@SuppressWarnings("rawtypes")
public class JuicerDemo {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new FileReader("config.txt"));
Juicer juicer = new Juicer();
String className = br.readLine();
Class c = Class.forName("cn.itcast.day26.reflect." + className); // 根据类名获取.class文件
Fruit f = (Fruit) c.newInstance(); // 使用指定的.class文件创建对象
String methodName = br.readLine();
Method m = Juicer.class.getMethod(methodName, Fruit.class); // 根据方法名获取方法
m.invoke(juicer, f); // 在juicer上执行方法
}
}
class Juicer { // 榨汁机
public void run(Fruit f) { // 榨汁方法, 传入水果, 调用水果被挤压的方法
f.squeeze();
}
public void pare(Fruit f) {
f.pare();
}
}
interface Fruit { // 水果
void squeeze(); // 挤压方法
void pare();
}
class Apple implements Fruit {
public void squeeze() {
System.out.println("榨出一杯苹果汁");
}
public void pare() {
System.out.println("削苹果皮");
}
}
class Orange implements Fruit {
public void squeeze() {
System.out.println("榨出一杯橘子汁");
}
public void pare() {
System.out.println("剥橘子皮");
}
}
class Mango implements Fruit {
public void squeeze() {
System.out.println("榨出一杯芒果汁");
}
public void pare() {
System.out.println("削芒果皮");
}
}