静态导入:
JDK1.5新特性,当使用一个类的静态成员和静态方法时,为了简化语法可以使用静态导入。
语法:import static 类.*(类.方法/变量);使用该类的静态变量时可以省略类名。
示例代码:
import static java.lang.System.*; class Demo { public static void main(String[] args) { //打印时可以直接省略System类名。 out.println("ssssss"); } } |
可变参数列表:
一个方法接受的参数不固定时,可以使用可变参数列表。可变参数列表实际上是将参数列表传到数组中进行操作。
有了可变参数,就不用显示地编写数组语法了,当你指定参数时编译器实际上会为你去填充数组,你获得的仍旧是一个数组,在每一种情况中,编译器都会使用自动包装机制来匹配重载方法。
当传入一个数组时,编译器判断其为数组,就不会再为你填充数组。
可以通过在某个方法中增加一个非可变参数来解决问题。
代码示例:
class Demo { static void f(float i,Character ... args) { Ssytem.out.println(); } static void f(Character...args) { System.out.println(args); } public static void main(String[] args) { f(1,'a'); f('1','b'); } } |
增强for循环:
语法:for( type 变量名:集合变量名) { };
注意事项:变量名必须在for循环内部进行定义。
集合变量可以是数组或是实现了Iterator借口的集合类。
自动装箱和自动拆箱:
Integer i = 3;//自动打包 int j = i+1;//自动拆包 |
对于基本类型数据,在打包成对象时,如果数据在一个字节之内,则将其暂存起来,下次使用时直接使用。
枚举:
关键字enum可以将一组具有名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用。
除了不能继承自一个enum之外,我们基本上可以将enum看作一个常规类。
Enum中添加构造方法和main方法:
public enum EnumDemo { WEST("xi"),NORTH("bei"),SOUTH("nan"),EAST("dong"); private String de; private EnumDemo(String str) { de = str; } public static void main(String[] args) { for(EnumDemoed : EnumDemo.values()) { System.out.println(ed+" "+ed.de); } } }
|
注意事项:
1. 如果定义自己的方法,那么必须在enum实例序列的最后添加一个分号。
2. 在定义方法之前必须定义enum实例。
3. 我们只能在enum定义的内部使用其构造器创建enum实例。
4. Enum的构造方法会在类加载时运行,进行其成员的初始化,enum定义结束后,编译器就不允许我们再使用其构造器来创建任何实例。
Switch语句中的enum:
一般情况下我们必须使用enum类型来修饰一个enum实例,但是在case语句中不必如此。
public enum EnumDemo { GREEN,YELLOW,RED; public static void main(String[] args) { EnumDemo color = EnumDemo.RED; switch(color) { case RED : color = EnumDemo.GREEN; break; case GREEN: color = EnumDemo.YELLOW; break; case YELLOW: color = EnumDemo.RED; break; } } } |
enum.valuse():
values()方法是由编译器添加的static方法。
使用借口组织枚举:
在一个借口内部,创建实现该接口的枚举,一次将元素进行分组,可以达到将枚举元素分类组织的目的
public interface Food { enum Appetizer implements Food { ASLAD,SOUP; } enum MainCourse implements Food { } enum Dessert implements Food { } } |
Enum类型实现了Food接口,那么我们就可以将其 实例 向上转型为food,所以上例中的所有东西都是Food。
使用EnumSet替代标志:
反射机制:
ClassLoader类加载机制:
通过Eclipse的run dialogue 查看详细的运行过程。 Java-Verbose:class
1. 并非一次性加载。
2. 需要时进行加载(运行期间动态加载)。
|
Bootstrap classLoader是系统类加载器,加载系统必须的类库,没有名字。返回为NULL
Extension classLoader是扩展类加载器。
Application classLoader是自定义类加载器。
|
程序运行过程
|
|
Java.lang.Class类:
Class保存的程序的字节码,当运行一个程序时,JVM虚拟机将字节码加载到内存中,Class类保存的信息:类的名字,类访问权限属性,字所属的包,字段信息,方法信息等等。
如何得到Class:
1. 类名.class 例如:System.class
2. 对象.class 例如:new String().class
3. Class.forName(“类名的全称”) 例如:Class.forName(“java.lang.String”); 常用
在java中所有的关键字,都是类,可以通过Class类取得这些。
java.lang.reflect.Constructor类:
Constructor
代表类中的构造方法。得到Constructor对象的方法:Constructor [] getConstructor(参数);
public static void main(String[] args)throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Person p = new Person(1,"chenqi"); //生成一个Person对象 Class c = p.getClass(); //获取Person类的Class对象 Constructor con = c.getConstructor(int.class,String.class); //获取带两个参数的构造方法 con.newInstance(1,"nihao"); //通过该构造对象生成一个对象 System.out.println(p); } } |
java.lang.reflect.Filed类:
Field
提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。
public static void main(String[] args)throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { Person p = new Person(3,"wr23"); Class c = p.getClass(); //获取p的Class对象 Field f = c.getDeclaredField("name"); //通过对象p的Class对象,获取名为 name 的 Field的对象。 f.set(p, "nihao"); //可以更改对象p的 f所指定的值。 System.out.println(f.get(p)); //获取值 } } |
java.lang.reflect.Method类:
Method
提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。
public class TestFiled { public static void main(String[] args)throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Person p = new Person(1,"chenqi"); Class c = p.getClass(); Method m = c.getMethod("setId",int.class); System.out.println(m); m.invoke(p, 10); System.out.println(p); } } |
javaBean:
javaBean是一个特殊的类,主要用来传递数据信息。特点:方法主要用来访问类中私有变量,符合一定的命名规则。
简单javaBean示例:
public class Person { public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } private int id; private String name; } |
通过内省操作javaBean:
PropertyDescriptor 描述 Java Bean通过一对存储器方法导出的一个属性。内省操作主要针对Javabean来的,简化了一系列反射的步骤;
比如反射一个方法需要首先获得字节码 class.forName();然后利用Constructor实例化,在获得method,然后在invoke这个方法;
而内省则只要一下几部即可:
PropertyDescriptor 其参数为(propertyName,obj.class)
第一个参数是bean的名称,命名规则如下:
getName 方法的propertyName是name。说明:去掉get、set修饰符剩下Name,如果第二个字母为小写则首字母也改成小写,所以最终变成name
setCPU 方法的propertyName是 CPU。说明:去掉get、set修饰符剩下CPU,如果第二个字母为大写则所有字符不变,所以最终变成CPU
第二个参数是需要改变类的字节码。
然后getWriteMethod().invoke(obj, value)即可;
public class Test { public static void main(String[] args) { try { //生成一个PropertyDescriptor进行对javaBean的内省操作 PropertyDescriptor pd = new PropertyDescriptor("id", Person.class); //将某一指定属性与此特性相关联。 pd.setValue("id",1); //获取id的值 System.out.println(pd.getValue("id")); } catch (IntrospectionException e) { e.printStackTrace(); } } } |
注解:(新特性)
Annotaticon:
Annotation表示的是一种注释的语法,在java最早的程序中提倡的是程序与配置代码分离,最新的理论是将所有的配置写入到代码之中。
JDK提供的三个内建注解:
@Deprecated 用 @Deprecated注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。在使用不被赞成的程序元素或在不被赞成的代码中执行重写时,编译器只会发出警告。 |
Override 表示一个方法声明打算重写超类中的另一个方法声明。如果方法利用此注释类型进行注解但没有重写超类方法,则编译器会生成一条错误消息。保证正确的复写操作。保存范围Runtime。 |
SuppressWarnings 表示压制警告,使不出现警告信息。SuppressWarnings类中有一个valuse的数组字段,所以SuppressWarnings可以同时压制多个警告信息。 格式:SuppressWarnings(“ ” , ” ”);或者 SupressWarnings(values= (“ ” , ” ”) ); |
注解结构图:
|
自定义Annotation:
定义Annotation的语法:public @interface Annotaticn的名称
使用Annotation的语法:在同一包下 @Annotaticn的名称
使用String
//自定义的Annotation public @interface MyAnnotation { //添加两个字段,并设置默认值。 public String key() default "nihao"; public String value() default "nimei"; }
@MyAnnotation (key="nihao",value="nimei") //这里的值可以设定,不进行设定将取默认值 public class Test { } |
使用枚举限定Annotation的取值。
public @interface MyAnnotation { public String key() default "nihao"; public String value() default "nimei"; //设置枚举属性,它的取值仅限定在枚举类型可以提供的几个 public Color color() default Color.RED; public String str []; //可以使用数组进行操作,如果只往数组传入一个值,可以直接写 str=” ” MyAnnotation ma = @MyAnnotation(value=””); //使用Annotation设置属性 } //枚举 public enum Color { RED("红色"),GREEN("绿色"),YELLOW("黄色"); private String info; Color(String arg0) { this.info = arg0; } } //实现 @MyAnnotation (key="nihao",value="nimei",color=Color.GREEN)//这里的值可以设定,不进行设定将取默认值 public class Test { } |
Retention和RetentionPolicy:(源注解)
java.lang.annotation包中定义了所有的与Annotation的操作。全部继承自Annotation接口。
Retention本身是一个Annotation,指示注释类型的注释要保留多久。其中的取值通过RetentionPolicy这个枚举类型指定的范围。如果注释类型声明中不存在Retention 注释,则保留策略默认为 RetentionPolicy.CLASS。
三个范围:
1. 只在源码中起作用:public static final RetentionPolicy SOURCE
2. 只在编译后的class文件中起作用:public static final RetentionPolicy CLASS
3. 在程序运行期间起作用:public static final RetentionPolicy RUNTIME(可以反射读取)。
注意:只有在Runtime范围内的Annotation才能被用户获取。
//自定义的Annotation @Retention(value = RetentionPolicy.RUNTIME) //修饰自定义的Annotation,表示Runtime范围 public @interface MyAnnotation { } |
反射与Annotation:
Annotation要起作用必须与反射机制相结合。通过反射可以取得在一个方法上声明的全部Annotation内容。
在Field、Method、Constructor的父类上提供了与Annotation操作的方法:
1. 获取全部的Annotation:public <T extendsAnnotation> T getAnnotation(Class<T> annotationClass)
2. 判断操作的是否是指定的Annotation:public booleanisAnnotationPresent(Class<? extends Annotation> annotationClass)
获取方法上的Annotation:
public class Test { @Override @Deprecated @SuppressWarnings(value="1") public String return "hello world"; } public static void main(String[] args) throws NoSuchMethodException, SecurityException { Class c = Test.class; Method m = c.getMethod("toString"); for(Annotation m1 : m.getAnnotations()) { System.out.println(m1); //@java.lang.Deprecated() } } } |
深入Annotation:
Java.lang.annotation下的 Target 、Documented、Inherited
l Target: 限制Annotation的使用范围。可以使用多个限定范围。
|
l Documented :指示某一类型的注释将通过 javadoc 和类似的默认工具进行文档化。应使用此类型来注释这些类型的声明:其注释会影响由其客户端注释的元素的使用。如果类型声明是用 Documented 来注释的,则其注释将成为注释元素的公共 API 的一部分。
l Inherited :表示当前Annotation可以继承。
泛型深入:
泛型是提供给javac编译器使用的,可以限定集合中的元素的类型,让编译器挡住非法输入,在生成的字节码文件中会去除这些类型信息,所以使用 getClass();获得的和原始类型相同。
参数化类型与非参数化类型兼容:
Collection<String> c = new List();
Collection c = new List<String>();
参数化类型与非参数化类型不存在继承:
Collection<Object>c = new ArrayList<String>();//错误
代理:
代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
要点:实现同一个接口,代理类调用和目标类相同的方法,并提供其他服务。
重要原则:不要把供货商暴漏给用户。
|
静态代理:
//目标类 public class Tank { void start() { System.out.println("运行"); } } //代理类 public class Test { Tank t; Test (Tank tank) { t = tank; } void start() { System.out.println(System.currentTimeMillis()); t.start(); System.out.println(System.currentTimeMillis()); } } |
动态代理:
l JVM可以在运行期动态生成类的字节码,这种动态生成的类往往被用作动态代理类。
l JVM生成的动态类必须实现一个或多个接口,所以动态代理类只能用作具有相同接口的目标类。
l JDK Complier, CGLIB ASM 库可以为没有实现接口的类生成一个子类,一个该类子类也可以作为该类的代理。
模拟 JDK 动态代理:
package com.bjsxt.proxy;
public class Client { public static void main(String[] args) throws Exception { Tank t = new Tank(); InvocationHandler h = new TimeHandler(t);
Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class, h);
m.move(); } } //可以对任意的对象、任意的接口方法,实现任意的代理
package com.bjsxt.proxy;
public interface Moveable { void move();
}
package com.bjsxt.proxy;
import java.util.Random;
public class Tank implements Moveable {
@Override public void move() {
System.out.println("Tank Moving..."); try { Thread.sleep(new Random().nextInt(10000)); } catch (InterruptedException e) { e.printStackTrace(); }
}
}
package com.bjsxt.proxy;
import java.lang.reflect.Method;
public interface InvocationHandler { public void invoke(Object o, Method m); }
package com.bjsxt.proxy;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
public class TimeHandler implements InvocationHandler{
private Object target;
public TimeHandler(Object target) { super(); this.target = target; }
@Override public void invoke(Object o, Method m) { long start = System.currentTimeMillis(); System.out.println("starttime:" + start); System.out.println(o.getClass().getName()); try { m.invoke(target); } catch (Exception e) { e.printStackTrace(); } long end = System.currentTimeMillis(); System.out.println("time:" + (end-start)); }
}
//生成代理的类 package com.bjsxt.proxy;
import java.io.File; import java.io.FileWriter; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader;
import javax.tools.JavaCompiler; import javax.tools.StandardJavaFileManager; import javax.tools.ToolProvider; import javax.tools.JavaCompiler.CompilationTask;
public class Proxy { public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception { //JDK6 Complier API, CGLib, ASM String methodStr = ""; String rt = "\r\n";
Method[] methods = infce.getMethods(); /* for(Method m : methods) { methodStr += "@Override" + rt + "public void " + m.getName() + "() {" + rt + " long start = System.currentTimeMillis();" + rt + " System.out.println(\"starttime:\" + start);" + rt + " t." + m.getName() + "();" + rt + " long end = System.currentTimeMillis();" + rt + " System.out.println(\"time:\" + (end-start));" + rt + "}"; } */ for(Method m : methods) { methodStr += "@Override" + rt + "public void " + m.getName() + "() {" + rt + " try {" + rt + " Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt + " h.invoke(this, md);" + rt + " }catch(Exception e) {e.printStackTrace();}" + rt +
"}"; }
String src = "package com.bjsxt.proxy;" + rt + "import java.lang.reflect.Method;" + rt + "public class $Proxy1 implements " + infce.getName() + "{" + rt + " public $Proxy1(InvocationHandler h) {" + rt + " this.h = h;" + rt + " }" + rt +
" com.bjsxt.proxy.InvocationHandler h;" + rt +
methodStr + "}"; String fileName = "d:/src/com/bjsxt/proxy/$Proxy1.java"; File f = new File(fileName); FileWriter fw = new FileWriter(f); fw.write(src); fw.flush(); fw.close();
//compile JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null); Iterable units = fileMgr.getJavaFileObjects(fileName); CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units); t.call(); fileMgr.close();
//load into memory and create an instance URL[] urls = new URL[] {new URL("file:/" + "d:/src/")}; URLClassLoader ul = new URLClassLoader(urls); Class c = ul.loadClass("com.bjsxt.proxy.$Proxy1"); System.out.println(c);
Constructor ctr = c.getConstructor(InvocationHandler.class); Object m = ctr.newInstance(h); //m.move();
return m; } } |