------- android培训、java培训、期待与您交流! ----------
1、枚举:
a) public abstract class Enum<E extends Enum<E>>extends Object implements Comparable<E>, Serializable
i. 这个类是所有 Java 语言枚举类型的公共基本类。
b) 用一个普通类来模拟枚举类:
i. 这个类必须是 abstract型的;
ii. 这个类必须是 static型的;
1. 因为一个枚举可变被定义到另个一个普通类的内部,并且枚举中的成员变量都是static型的本枚举类对象。
iii. 这个类的构造函数必须是private型的;
iv. 这个类中的成员变量(也即是枚举元素的变量)必须是 public型的、final型的、static型的本类类型对象;
v. 这个类中的其他成员变量(也即非枚举元素的变量)必须是private型的;
vi. 这个类中的其他相关成员函数必须是publici型的、abstract型的;
vii. 这个类中的其他成员函数不做要求。
viii. 最好实现java.lang.Comparable接口。因为Enum默认实现了java.lang.Comparable接口。
ix. 用一个普通类来模拟枚举类的示例:
abstract static class WeekDay1 {
private WeekDay1(){}
public final static WeekDay1 SUN = new WeekDay1(){
@Override
public WeekDay1 nextDay() {
// TODO Auto-generated method stub
return MON;
}
};
public final static WeekDay1 MON = new WeekDay1(){
@Override
public WeekDay1 nextDay() {
// TODO Auto-generated method stub
return SUN;
}
};
public abstract WeekDay1 nextDay();//必须得有这么一句。否则,WeekDay1型的对象无法访问到nextDay()方法。
public String toString(){
return this==SUN?"SUN":"MON";
}
}
c) 可以在一个main函数中这样来使用枚举:(这个枚举类定义在一个外部类的内部)
外部类名.WeekDay1 sun=外部类名.WeekDay1.SUN;
sop(sun.nextDay());
d) 枚举只有一个成员时,就可以作为一种单例的实现方式。
i. 也即还可以使用只有一个成员的枚举来实现一个单例设计模式。
关于强制类型转换:
1、强制类型转换的条件:
a) 必须在一对子父类之间;
b) 必须存在多态;
i. 也即只有 父类名称父类变量名称=子类对象实例 ;时才可以把这个父类变量名称强制转换成子类对象的引用;
1. 也即只有父类名称父类变量名称 = 子类对象实例 ; 才能 子类名称 子类变量名称 = (子类名称) 父类变量名称 ;
c) 因此 Object[] objArr = new Object[]{“aaa”,”bb”} ;
不能这样转换: String[] strArr = (String[]) objArr ;
d) 如果 Object[] objArr = new String[]{“aaa”,”bb”} ; 那么才可以转换成 String[] strArr = (String[]) objArr ;
e) 这些都是经过验证的!!
2、关于框架和工具类:在开发程序过程中
a) 我调用别人的类,这个被调用的类就工具类;
b) 别人的类调用我的类,这个别人的类就是框架。
3、由一个小问题引发的:
a) 编译失败代码:
int [] a1 = new int[]{1,2,3};
String [] a4 = new String[]{"a","b","c"};
System.out.println(a1.getClass() == a4.getClass());//编译失败为什么?
b) 出错提示:
---------- javac ----------
HelloWorld.java:33: 不可比较的类型:java.lang.Class<capture#734 of ? extends int[]> 和 java.lang.Class<capture#774 of ? extends java.lang.String[]>
System.out.println((a1.getClass()) = = (a4.getClass()));
^
1 错误
输出完成 (耗时 0 秒) - 正常终止
c) 而写成:
int [] a1 = new int[]{1,2,3};
String [] a4 = new String[]{"a","b","c"};
Class clazz1=a1.getClass();
Class clazz3=a4.getClass();
System.out.println(clazz1 == clazz3);
就不会出错了。
d) 解决问题:
int [] a1 = new int[]{1,2,3};
String [] a4 = new String[]{"a","b","c"};
System.out.println(a1.getClass() == a4.getClass());//编译失败 为什么?
刚才又看了看 getClass方法的API文档。
原来是在java 5之后
a1.getClass() 返回的是一个Class<? extends int[]>类型的实例对象;
a4.getClass() 返回的是一个Class<? extends String[]>类型的实例对象。
直接让a1.getClass()、a4.getClass()通过==比较肯定会造成类型不兼容的问题。
如果这么写:
Class clazz1=a1.getClass(); //不会出错时因为把a1.getClass()的 Class<? extends int[]>进行了向上转型转成了 Class类型的啦。
Class clazz3=a4.getClass();//不会出错时因为把a4.getClass()的 Class<? extends String[]>进行了向上转型转成了 Class类型的啦。
System.out.println(clazz1 == clazz3);
其实通过equals方法来比较就可以了,也即这样写System.out.println((a1.getClass()).equals(a4.getClass()));也不会出错。
至于张老师讲课的时候,为啥直接这样写 System.out.println(a1.getClass() == a4.getClass()); 还能编译通过。
我个人认为可能是张老师的Eclipse使用的jdk版本在1.5之之前(1.5之前没有泛型)吧。(貌似我记得张老师头几天讲课时把这个程序的workspace的编译环境故意设置底了点)这个我只是猜想,没有再回过头去验证。
e) 总结:
i.
1. == 是比较两个同类型的对象的引用的地址值是否相同;
2. equals方法可以比较任意的两个对象的……是否相同。
ii. (java API原话)getClass方法的实际结果类型是 Class<? extends |X|>,其中 |X| 表示清除表达式中的静态类型,该表达式调用 getClass。
例如,以下代码片段中不需要强制转换:
Number n = 0;
Class<? extends Number> c = n.getClass();
类加载器:
1、ClassLoader类加载器:
a) 类加载器用于把硬盘上的 *.class文件加载到内存中来,然后再对它进行一些处理,处理完的结果就是字节码。而这一系列工作都是类加载器在干。
i. 类加载器是负责加载类的对象;
ii. 类加载器也可以加载非*.class的普通文件。
1. 通过getResource (String name) 等等几个方法来加载普通文件。
b) 类加载器的用途:类加载器只能加载classpath环境下的各种文件。(也即类加载器不止能加载*.class文件,也能加载非class的其他普通文件。)
i. 使用类加载器ClassLoader对象的getResourceAsStream(String name)方法和getResource(String name)等方法加载classpath路径环境变量下的某个文件时。
1. 这些方法里面的实参一定不能用 / 打头,说明这个实参字符串表示的路径是一个相对路径,相对于classpath所标示的路径。
a) 如果这个文件在(classpath路径的下几层)目录中。那么这些方法的参数name就一定要写上这个下几层目录。否则在运行时,将会抛出 NullPointerException异常。
ii. 而对于直接通过Class对象实例的getResourceAsStream(String name)等方法得到的这个文件。这里的name实参一般情况下,可以直接写这个文件的文件名,而不用去理会这个文件位于classpath路径下的那个文件夹(java包)中。(因为一般情况下,这个文件就位于classpath路径下的某个java包中,和这个Class对象实例位于同一个包中)实例见 ReflectTest2.java文件。
1. //InputStream ips = ReflectTest2.class.getResourceAsStream(“config.properties”);//这个参数没有用 / 打头,说明这个字符串表示的路径是一个相对路径,相对于ReflectTest2.class文件所在的路径。使用相对路径,一定不能使用 / 打头。如果使用/ 打头了,就表示这是一个绝对路径了。
2. InputStream ips = ReflectTest2.class.getResourceAsStream(“/cn/itcast/javaenhance/config.properties”);//这个参数用 / 打头,说明这个字符串表示的路径是一个绝对路径。从classpath指定的路径开始的绝对路径。并且使用这个绝对路径时,必须要用 / 打头。如果没有使用/ 打头了,就表示这是一个相对路径了。
iii. SSH这三种框架的加载配置文件的原理:就是使用的这个类加载器ClassLoader的方式来加载配置文件的。
iv. eclipse的原理:
1. 编译:
a) “外部路径”默认为eclipse的"java build path"的source页签中设置的"output folder"的路径;
b) “内部路径”即为.java文件的包路径;
2. 执行:
a) 对.java文件的“package”一项做编译检查,
b) package中的路径必须与.java文件存放的路径完全一致;
c) 这样右键.java文件执行时,
d) eclipse会自动根据.java文件存放的路径构建完整的包路径执行。
c) 系统默认的三个的类加载器BootStrap、ExtClassLoader、AppClassLoader他们之间并没有什么继承关系,但是这三种加载器之间具有一种委托的上下级的关系。
i. 比如BootStrap就不是用java语言编写的;
ii. 并且ExtClassLoader和AppClassLoader都是sun.misc.Lancher的内部类: sun.misc.Launcher$AppClassLoader
和sun.misc.Launcher$ExtClassLoader
iii. 并且ExtClassLoader和AppClassLoader都是java.net.URLClassLoader的子类
1. java.net.URLClassLoader类是J2SE 的标准类,它的父类是SecureClassLoader,而SecureClassLoader 是继承自ClassLoader 类的。
iv. 现在整个关系应该很清楚,几乎所有的ClassLoader 实现都是继承URLClassLoader 的。(也即几乎所有的加载器,都是继承自URLClassLoader 的)
内省:
1、内省:
a) JavaBean中一定要有一个不带参数的构造方法。
b) JavaBean必须是一个public型的类或者接口。
c) JavaBean的属性必须是private型的。
2、java7的一个新特性:
a) 可以这样定义一个map集合:
i. Map map = { name:"zxx", age:18};
3、内省的几个常用类:
a) PropertyDescriptor ;
b) IntroSpector ;
c) BeanInfo ;
BeanUtils包中的类:(BeanUtils包中的BeanUtils类和PropertyUtils类是操作java bean 的最常用的类了)
d) BeanUtils ;
i. BeanUtils的方法:
1. copyProperties(……); //用于拷贝一个java bean上的所有属性到另一个java bean上。
2. describe(……); //用于把一个java bean上的所有属性转换到一个Map集合里面去,并返回这个Map集合。(这个方法比较常用)
3. populate(……); //用于把一个Map集合上的键值对(根据键和一个对应java bean上的属性间的对应关系)填充到这个java bean上的属性上去。
a) 由此可知:copyProperties方法和describe方法用于java bean的属性和Map集合之间进行相互转换!
4. 且BeanUtils类的getProperty和setProperty方法不仅可以操作java bean,而且还可以操作Map集合。因为Map集合和java bean很类似!
e) PropertyUtils ;
f) 这两个类里面都有getProperty和setProperty方法。
i. 但是这两个类里面的这两个方法传入的参数有些不同。
1. BeanUtils类的get属性时返回的结果为字符串,set属性时可以接受任意类型的对象,但通常我们使用字符串来设置一个属性。
2. PropertyUtils类的的get属性时返回的结果为这个属性的本身的数据类型的数据,set属性时只能接受这个属性的本身的数据类型的数据。
a) 比如这个属性本身是一个int型的。那么set属性时,就接受一个int型的数据;在get属性时,返回的结果为这个int型的包装类Integer类型的对象。