枚举:枚举就相当于一个类,其中也可以定义构造方法,成员变量,普通方法和抽象方法;
枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后面要有分号与其他成员分隔,把枚举中的成员方法或变量等放在枚举元素的的前面,编译器报错.
带构造方法的枚举:
构造方法必须是私有的
如果有多个构造方法,直接在元素后用()调用
枚举元素MON和MON()的效果一样,都是调用默认的构造方法
枚举只有一个成员时,就可以作为一种单例的实现方式.
package mypackage.gaoxin;
publicenum TrificLamp {
RED(30) {
@Override
public TrificLamp nextLamp() {
returnGREEN;
}
},
GREEN(45) {
@Override
public TrificLamp nextLamp() {
returnYELLOW;
}
},
YELLOW(5) {
@Override
public TrificLamp nextLamp() {
returnRED;
}
};
privateinttime;
private TrificLamp(int time) {
this.time = time;
}
publicabstract TrificLamp nextLamp();
}
反射的基石:Class类
Java程序中的各个Java类属于同一类事物,描述这类事物的java类名就是Class,它的实例对象就是对应各个类在内存中的字节码.
得到字节码:
类名.clas s;
对象.getClass();
Class.forName(“java.lang.string”);
Java中的9个基本数据类型(boolean,byte,char,short,int,long,double,float,void)
Class.isPrimitive() 判断是否为基本数据类型
Int.Class==Integer.TYPE
数组类型的Class实例对象Class.isArray()判断
反射:反射就是把Java类中的各种成分映射成相应的java类,
例如:一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息业用一个个的Java类来表示,就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类.表示java类的Class类显然要提供一系列的方法,来获取其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,它们是Field,Method,Contructor,Package等等.
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调用Class类的方法可以得到浙西实例对象后,得到浙西实例对象后有什么用呢,这正好似学习和应用反射的要点
反射方式创建实例对象:
Constructor construct = String.class.getConstructor(StringBuffer.class);
String str = (String) construct.newInstance(new StringBuffer(
"helloword"));
取对象:
package re;
import java.lang.reflect.Field;
publicclass test {
publicstaticvoid main(String[] args) throws Exception {
ReflectPoint rp1=new ReflectPoint(3, 5);
Field fieldX= rp1.getClass().getField("x");
Field fieldY=rp1.getClass().getDeclaredField("y");
fieldY.setAccessible(true);
System.out.println(fieldX.get(rp1));
System.out.println(fieldY.get(rp1));
}
}
class ReflectPoint{
publicintx;
privateinty;
public ReflectPoint(int x, int y) {
this.x = x;
this.y = y;
}
}
反射技术开发框架原理:
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.Properties;
publicclassReflectTest {
publicstaticvoid main(String[] args) throws Exception {
// 切记使用完整的路径,但完整的路径不是硬编码,
// InputStream is = newFileInputStream("config.properties");
InputStreamis = ReflectTest.class.getResourceAsStream("default/config.properties");
Propertiesprop = newProperties();
prop.load(is);
Collectioncollections = (Collection) Class.forName(
prop.getProperty("className")).newInstance();
ReflectPointrp1 = newReflectPoint(3, 3);
ReflectPointrp2 = newReflectPoint(5, 2);
ReflectPointrp3 = newReflectPoint(3, 3);
collections.add(rp1);
collections.add(rp2);
collections.add(rp3);
collections.add(rp1);
System.out.println(collections.size());
}
}
内省:
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
publicclassIntroSpectortest {
/**
* @param args
* @throws Exception
*/
publicstaticvoid main(String[] args) throws Exception {
ReflectPointrfp1 = newReflectPoint(3, 8);
StringpropertyName = "x";
getProperty(rfp1,propertyName);
setProperty(rfp1,propertyName,6);
getProperty(rfp1,propertyName);
}
privatestaticvoid setProperty(Object o,String propertyName, int val)
throws IntrospectionException,IllegalAccessException,
IllegalArgumentException,InvocationTargetException {
PropertyDescriptorpd = newPropertyDescriptor(propertyName,
o.getClass());
MethodmethodSet = pd.getWriteMethod();
methodSet.invoke(o,val);
}
privatestaticvoid getProperty(Object o,String propertyName)
throws IntrospectionException,IllegalAccessException,
InvocationTargetException{
PropertyDescriptorpd = newPropertyDescriptor(propertyName,
o.getClass());
MethodmethodGet = pd.getReadMethod();
ObjectretVal = methodGet.invoke(o, null);
System.out.println(retVal.toString());
}
}
BeanUtils:
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
publicclassIntroSpectortest {
/**
* @param args
* @throws Exception
*/
publicstaticvoid main(String[] args) throws Exception {
ReflectPointrfp1 = newReflectPoint(3, 8);
StringpropertyName = "x";
getProperty(rfp1,propertyName);
setProperty(rfp1,propertyName,6);
getProperty(rfp1,propertyName);
System.out.println(BeanUtils.getProperty(rfp1,propertyName));
//传参可以使用字符串
BeanUtils.setProperty(rfp1,propertyName, "4");
//查看返回的类型,返回String
System.out.println(BeanUtils.getProperty(rfp1,propertyName).getClass().getName());
//传参只能传属性对应的类型
PropertyUtils.setProperty(rfp1,propertyName, 9);
//查看返回的类型,为Integer
System.out.println(PropertyUtils.getProperty(rfp1,propertyName).getClass().getName());
}
privatestaticvoid setProperty(Object o,String propertyName, int val)
throws IntrospectionException,IllegalAccessException,
IllegalArgumentException,InvocationTargetException {
PropertyDescriptorpd = newPropertyDescriptor(propertyName,
o.getClass());
MethodmethodSet = pd.getWriteMethod();
methodSet.invoke(o,val);
}
privatestaticvoid getProperty(Object o,String propertyName)
throws IntrospectionException,IllegalAccessException,
InvocationTargetException{
PropertyDescriptorpd = newPropertyDescriptor(propertyName,
o.getClass());
MethodmethodGet = pd.getReadMethod();
ObjectretVal = methodGet.invoke(o, null);
System.out.println(retVal.toString());
}
}
注解:相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加则等于没有某种标记,以后,javac编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事,标记可以加在包,类,字段,方法,方法的参数以及局部变量上。
@Deprecated,过时注解
@Override,重载注解
@SuppressWarnnings压缩警告
注解类:
@interface A{}
应用了“注解类”的类
@A
Class B{}
对”应用了注解类的类”进行反射操作的类
Class C{
If(B.class.isAnnotionPresent(A.class) )
A a=B.class.getAnnotion(A.class);
}
注解的生命周期:java源文件 编译器à class文件类加载器à 内存中的字节码
分别是: @Retention(RetentionPolicy.SOURCE)
@Retention(RetentionPolicy.CLASS)
@Retention(RetentionPolicy.RUNTIME)
注解的属性跟接口中的方法类似
package myjava.test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
@interfaceMyAnnotation {
String color() default"blue";
String value(); //value是默认的,在只设置一个属性值的时候可以省略"value="
int[] arrayAttr() default {1,2,3};
}
package myjava.test;
@MyAnnotation(color = "red", value = "xyz", arrayAttr = { 1, 2, 3 })
publicclass AnnotationTest {
@MyAnnotation("ada")
publicstaticvoid main(String[] args) throws Exception {
// TODO Auto-generatedmethod stub
if (AnnotationTest.class.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation a = (MyAnnotation) AnnotationTest.class
.getAnnotation(MyAnnotation.class);
System.out.println(a.color());
System.out.println(a.value());
System.out.println(a.arrayAttr().length);
}
}
}
泛型:泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住员程序中的非法输入,编译器编译带类型说明的集合时会去除掉类型”信息”,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样,由于编译器生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,在调用其add方法即可.
实例:
package mypackage.gaoxin;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
publicclass GenericTest {
publicstaticvoid main(String[] args) throws IllegalAccessException,IllegalArgumentException, InvocationTargetException, NoSuchMethodException,SecurityException {
ArrayList<Integer> al=new ArrayList<Integer>();
al.getClass().getMethod("add", Object.class).invoke(al, "hahaha");
System.out.println(al.get(0));
}
}
术语:
1.整个称为ArrayList<E>泛型类型
2.ArrayList<E>中的E称为类型变量或类型参数
3.整个ArrayList<Integer>称为参数化的类型
4. ArrayList<Integer>中的Integer称为类型参数的实例或实际参数
5. ArrayList<Integer>中的<>念着typeof
6. ArrayList称为原始类型
参数化类型与原始类型的兼容性
参数化类型可以引用以个原始类型的对象,编译报告警告,例如,
Collection<String> c=new Vector();
原始类型可以引用一个参数化的类型对象,编译报告警告,例如,
Collection c1=newVector<String>();
参数化类型不考虑类型参数的继承关系:
Vector<String> v=new Vector<Object>();//错误
Vector<Object> v = new Vector<String>();//也错误
在创建数组时,数组的元素不能使用参数化的类型,例如下面的语句有错误:
Vector<Integer> vectorList[]=new Vector<Integer>[10];
泛型中的 ? 通配符:
使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用做引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法.
show(new ArrayList<String>());
publicstaticvoid show(Collection<?> col){
for(Object obj:col){
System.out.println(obj);
}
}
限定通配符的上边界:
Vector<? extends Number>x=new Vector <Integer>();
限定通配符的下边界:
Vector<? Super Integer> x= new Vector<Number>();
综合应用:
package mypackage.gaoxin;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
publicclass GenericTest2 {
publicstaticvoid main(String[] args) {
HashMap<String,Integer> maps=new HashMap<String, Integer>();
maps.put("tanhui", 100);
maps.put("lizheng", 80);
maps.put("zhaojia", 60);
Set<Map.Entry<String, Integer>>entrySet=maps.entrySet();
for(Map.Entry<String, Integer> entry: entrySet){
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
}
自定义泛型方法:
package mypackage.gaoxin;
publicclass GenericTest3 {
publicstaticvoid main(String[] args){
int i=show(3,4);
System.out.println(i);
}
/**
* 定义泛型方法返回泛型T,在返回值前面的<T>表示声明以个泛型
*/
publicstatic <T> T show(T a,T b){
return b;
}
}
注意:只有引用类型才能作为泛型方法的参数.
package mypackage.gaoxin;
publicclass GenericTest3 {
publicstaticvoid main(String[] args){
show(newint[]{1,2,3,4,5},3,2); //报错
show(new Integer[]{1,2,4,5,3,6},3,5);
}
/**
* 定义泛型方法返回泛型T,在返回值前面的<T>表示声明以个泛型
*/
publicstatic <T> void show(T[] a,int i,int j){
T temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
自定义泛型类:
package mypackage.gaoxin;
publicclass GenericDao<E> {
publicboolean save(E obj) {
returntrue;
}
publicboolean update(E obj) {
returntrue;
}
publicboolean delete(E obj) {
returntrue;
}
public E findById(int id) {
returnnull;
}
}
测试类:
package mypackage.gaoxin;
publicclass GenericDaoTest {
publicstaticvoid main(String[] args) {
GenericDao<ReflectPoint> gc = newGenericDao<ReflectPoint>();
ReflectPoint rp;
gc.save(new ReflectPoint(3, 3));
gc.delete(new ReflectPoint(4, 4));
rp = gc.findById(3);
gc.delete(rp);
}
}
通过反射获得泛型的实际类型参数:
package mypackage.gaoxin;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.Vector;
publicclass GenericDaoTest {
publicstaticvoid main(String[] args) throws Exception{
Method applyMethod=GenericDaoTest.class.getMethod("applyVector", Vector.class);
Type[] types=applyMethod.getGenericParameterTypes();
ParameterizedType pt=(ParameterizedType)types[0];
System.out.println(pt.getRawType());
System.out.println(pt.getActualTypeArguments()[0]);
}
publicstaticvoid applyVector(Vector<Date> v){
}
}
类加载器及其委托机制:
系统默认的三个主要类加载器,每个类加载器加载特定位置的类
BootStrap(不是java对象,嵌套在jvm中;JRE/lib/rt.jar)
ExtClassLoader(JRE/lib/ext/*.jar)
AppClassLoader(ClassPath指定的所有jar或目录)
加载的顺序:
首先当前线程的类加载器(可通过getContextClassLoader(),和set ContextClassLoader()来获取,设置)去加载线程中的第一个类
如果类A中引用了类B,Java虚拟机将使用加载类A的加载器来加载类B
每个类加载器加载是,有先委托给其上级类加载器,
如果上级类加载器已经加载成功,则不在往下委托给子类加载器
当所有祖宗加载器没有加载到类时,回到发起者类加载器,
还加载不了则抛出ClassNotFoundException
AOP(Aspect Oriented program):
l 系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方面,如下所示:
安全 事务 日志
StudentService ------|----------|------------|-------------
CourseService ------|----------|------------|-------------
MiscService ------|----------|------------|-------------
l 用具体的程序代码描述交叉业务:
method1 method2 method3
{ { {
------------------------------------------------------切面
.... .... ......
------------------------------------------------------切面
} } }
l 交叉业务的编程问题即为面向方面的编程(Aspect orientedprogram ,简称AOP),AOP的目标就是要使交叉业务模块化。可以采用将切面代码移动到原始方法的周围,这与直接在方法中编写切面代码的运行效果是一样的,如下所示:
------------------------------------------------------切面
func1 func2 func3
{ { {
.... .... ......
} } }
------------------------------------------------------切面
l 使用代理技术正好可以解决这种问题,代理是实现AOP功能的核心和关键技术。
动态代理技术:
l 要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情!写成百上千个代理类,是不是太累!
l JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
l JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。
l CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,那么可以使用CGLIB库。
l 代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码:
Ø 1.在调用目标方法之前
Ø 2.在调用目标方法之后
Ø 3.在调用目标方法前后
Ø 4.在处理目标方法异常的catch块中
动态代理的工作原理图:
package mypackage.gaoxin;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
publicclass ProxyTest {
publicstaticvoid main(String[] args) {
Collection proxy = (Collection) Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[] { Collection.class }, new InvocationHandler() {
ArrayList target = new ArrayList();
@Override
public Objectinvoke(Object proxy, Method method,
Object[] args) throws Throwable {
long beginTime = System.currentTimeMillis();
Object reval = method.invoke(target, args);
long endTime = System.currentTimeMillis();
System.out.println(method.getName()
+ "Running time of:" + (endTime -beginTime));
return reval;
}
});
proxy.add("tanhui");
proxy.add("lizheng");
proxy.add("zhaojia");
System.out.println(proxy.size());
}
}