---------- android培训、java培训、java学习型技术博客、期待与您交流! ----------
1、import static语句导入一个类中的某个静态方法或所有静态方法。
举例:import static java.lang.Math.sin;
2、可变参数:方法接收的参数个数不定
int add(int ...args):在方法内部可以把args当做数组操作
3、For增强语法:
for ( type 变量名:集合变量名 ) { … }
注意事项:
迭代变量必须在( )中定义!
集合变量可以是数组或实现了Iterable接口的集合类
4、自动装箱:Integer num = 12;
5、自动拆箱:System.out.println(num + 12)
基本数据类型中还涉及了对象缓存:-128~127(一个字节大小),创建一个对象之后会缓存到一个池里,称为享元模式。
6、枚举是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。当枚举中只有一个元素时,可以作为一种单例的实现方式。
【代码】
public class EnumTest {
public static void main(String[] args) {
//枚举基础使用
WeekDay weekday = WeekDay.FRI;
System.out.println(weekday);//打印FRI,为我们实现了toString方法
System.out.println(weekday.name());//返回字符串
System.out.println(weekday.ordinal());//获取索引,从0开始
//将字符串变成WeekDay对象
System.out.println(WeekDay.valueOf("SUN").toString());
//变成数组,获取长度
System.out.println(WeekDay.values().length);
}
//带抽象方法的枚举类
public enum TrafficLamp{
RED(30){
public TrafficLamp nextLamp(){
return GREEN;
}
},
GREEN(45){
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;
}
}
//定义一个枚举
public enum WeekDay{
SUN(1),MON(),TUE(),WED,THI,FRI,SAT;
private WeekDay(){//默认调用无参构造
System.out.println("one");
}
private WeekDay(int day){
System.out.println("two");
}
}
}
7、反射:Java程序中的各个java类属于同一类事物,描述这类事物的java类名就是Class。
Class用来描述众多的java类。它的各个实例对象是类的字节码。得到字节码有三种方法。
(1)对象.getClass()
(2)类名.Class
(3)Class.forName(“java.lang.String”);
虚拟机缓存有字节码,就返回,没有的话就是用类加载器加载,并缓存在java虚拟机里,以便以后使用
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,如int[] void
反射就是把Java类中的各种成分映射成相应的java类。
反射会导致程序性能下降
(1)变量对应Filed类:
//----------反射之--字段------------
ReflectPoint pt1 = new ReflectPoint(3,5);
ReflectPoint pt2 = new ReflectPoint(6,10);
//获取字节码上的变量Y。fieldY只代表字段,具体的值在不同的对象上都不同
Field fieldY = pt1.getClass().getField("y");
System.out.println(fieldY.get(pt1));
System.out.println(fieldY.get(pt2));
//private字段
Field fieldX = pt1.getClass().getDeclaredField("x");
fieldX.setAccessible(true);//暴力访问
System.out.println(fieldX.get(pt1));
System.out.println(fieldX.get(pt2));
//一定要会这个程序,a改为b,obj中有String变量
private static void changeStringValue(Object obj) throws IllegalArgumentException, IllegalAccessException {
Field[] fields = obj.getClass().getDeclaredFields();
for(Field field : fields){
//字节码才一份,用==,比较符合
//字段的类型是什么
if(field.getType()==String.class){
String oldValue = (String)field.get(obj);
String newValue = oldValue.replace('b', 'a');
//重新设置值
field.set(obj, newValue);
}
}
}
(2)方法对应Method类:
Method methodCharAt = str1.getClass().getMethod("charAt", int.class);
//调用字节码的charAt方法,使用哪个对象啊
char ch = (Character)methodCharAt.invoke(str1, 1);
System.out.println(ch);
(3)构造方法对应Constructor:提供了一个newInstance方法创建对象,参数类型要与获得Constructor时的参数一致。
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
String str2 = (String)constructor1.newInstance(new StringBuffer("abcd"));
(4)数组的反射作用:
int[] arr = {1,2,3,4,5};
printObject(arr);
private static void printObject(Object obj) {
Class clazz = obj.getClass();
if (clazz.isArray()) {
//获得哪个数组的长度啊
int len = Array.getLength(obj);
for (int i=0;i<len;i++) {
System.out.println(Array.get(obj, i));
}
} else {
System.out.println(obj);
}
}
反射主要是实现框架功能:在编写框架时,要调用用户提供的类,但是不知道类叫什么,只能通过用户传进来的参数实例化对象。
8、内省操作:它主要用于对JavaBean进行操作,JavaBean是一种特殊的Java类,其中的某些方法符合某种命名规则,如果一个Java类中的一些方法符合某种命名规则,则可以把它当作JavaBean来使用。也了解了java7的Map的新特性。
ReflectPoint pt = new ReflectPoint(3,5);
//如果当做普通类来操作,很麻烦
String propertyName = "x";
//"x"-->"X"-->getX()-->methodGetX-->invoke
//属性扫描,PropertyDescriptor 描述 Java Bean 通过一对存储器方法导出的一个属性。
PropertyDescriptor pd = new PropertyDescriptor(propertyName,pt.getClass());
//得到x属性的读方法
Method methodGetX = pd.getReadMethod();
//调用读方法
System.out.println(methodGetX.invoke(pt));
//获取写方法,更改x的值
Method methodSetX = pd.getWriteMethod();
methodSetX.invoke(pt, 30);
//调用读方法
System.out.println(methodGetX.invoke(pt));
9、注解相当于一种标记,在程序中加了注解就等于为程序打上了某种标记,没加,则等于没有某种标记,以后,javac 编译器,开发工具和其他程序可以用反射来了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事。标记可以加在包,类,字段,方法,方法的参数以及局部变量上。
//注解可作用在哪里
@Target(ElementType.TYPE)
//注解保存到那个步骤
@Retention(RetentionPolicy.RUNTIME)
public @interface ItcastAnnotation {
String value();//添加字符串属性
int[] arrayattr();//添加数组属性
}
//当只有一个value属性时,可以不用写value=
@ItcastAnnotation(value="xyz",arrayattr={1,2,3}/*2*/,lamp=TrafficLamp.GREEN,annotationAttr=@MetaAnnotation("yyy"))
public class AnnotationTest {
public static void main(String[] args) {
Class clz = AnnotationTest.class;
Class itcastClz = ItcastAnnotation.class;
//ItcastAnnotation在不在啊
if (clz.isAnnotationPresent(itcastClz)) {
//获得Annotation
ItcastAnnotation annotation = (ItcastAnnotation)clz.getAnnotation(itcastClz);
System.out.println(annotation);
//打印字符串属性
System.out.println(annotation.value());
//打印数组属性
for(int i : annotation.arrayattr()){
System.out.println(i);
}
}
}
}
10、泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去除掉“类型”信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其它类型的数据,例如,用反射得到集合,再调用其add方法即可。
【基本应用】
public class GenericTest {
public static void main(String[] args) throws Exception {
//表名ArrayList只能存String
ArrayList<String> list = new ArrayList<String>();
list.add("java01");
list.add("java02");
//取的话,是String类型的
String str = list.get(1);
System.out.println(str);
//表名构造函数时String类的,在newInstance时就不用强制类型转换了
Constructor<String> c = String.class.getConstructor(StringBuffer.class);
String str1 = c.newInstance(new StringBuffer("abc"));
System.out.println(str1.charAt(1));
}
}
泛型是提供给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合时会去掉“类型信息”,使程序运行效率不受影响。对于参数卷的泛型类型,getClass()方法的返回值和原始类型完全一样。由于编译生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中添加其他类型的数据。如利用反射。
ArrayList<E>类定义和ArrayList<Integer>类引用中涉及如下术语:
(1)整个称为ArrayList<E>泛型类型
(2)ArrayList<E>中的E称为类型变量或类型参数
(3)整个ArrayList<Integer>称为参数化的类型
(4)ArrayList<Integer>中的Integer称为类型参数的实例或实际类型参数
(5)ArrayList<Integer>中的<>念着typeof
(6)ArrayList称为原始类型
参数化类型与原始类型的兼容性:
(1)参数化类型可以引用一个原始类型的对象,编译报告警告,例如,
(2)Collection<String> c = new Vector();//可不可以,不就是编译器一句话的事吗?
(3)原始类型可以引用一个参数化类型的对象,编译报告警告,例如,
(4)Collection c = new Vector<String>();//原来的方法接受一个集合参数,新的类型也要能传进去
【实验】
Vector<String> v = new Vector();
Vector v1 = new Vector<String>();
添加元素时,add方法参数类型和get方法的返回类型看左侧
参数化类型不考虑类型参数的继承关系:
(1)Vector<String> v = new Vector<Object>(); //错误!///不写<Object>没错,写了就是明知故犯
(2)Vector<Object> v = new Vector<String>(); //也错误!左边明确说可以装所有类型,但是右边只装了String,矛盾了
编译器不允许创建泛型变量的数组。即在创建数组实例时,数组的元素不能使用参数化的类型,例如,下面语句有错误:
Vector<Integer> vectorList[] = new Vector<Integer>[10];
泛型中的?通配符
使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。
限定通配符的上边界:
正确:Vector<? extends Number> x = new Vector<Integer>();
是Number的子类,最高是Number
错误:Vector<? extends Number> x = new Vector<String>();
限定通配符的下边界:
正确:Vector<? super Integer> x = new Vector<Number>();
是Integer的父类,最低是Integer
错误:Vector<? super Integer> x = new Vector<Byte>();
泛型综合应用案例
HashMap<String,Integer> map = new HashMap<String,Integer>();
map.put("01", 10);
map.put("02", 20);
map.put("03", 30);
//Set里面装的是Map.Entry,Entry里面装的是<String, Integer>
Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
//遍历
for(Map.Entry<String, Integer> entry : entrySet){ System.out.println(entry.getKey()+"="+entry.getValue());
}
11、类加载器:
(1)Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader
(2)类加载器也是Java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是不是java类,这正是BootStrap。
(3)Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载
12、代理:
动态代理技术:
1.JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
2.JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作具有相同接口的目标类的代理。
代理类的各个方法中通常除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码:
1.在调用目标方法之前
2.在调用目标方法之后
3.在调用目标方法前后
4.在处理目标方法异常的catch块中
public class MyProxy {
private Person p = new Zhangsan();
//Demo----
Person person = MyProxy.createProxy(); person.sing(”爱你爱你“) person.dance();
public Person createProxy(){
return (Person) Proxy.newProxyInstance(MyProxy.class.getClassLoader(), p.getClass().getInterfaces(),new InvocationHandler(){
/*
* proxy:把代理对象自身传递进来
* method:代表当前调用的方法
* args:调用方法的参数
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodname = method.getName();
if(methodname.equals("sing")){
System.out.println("吃饭啦!!");
return method.invoke(p, args);
}else if(methodname.equals("dance")){
System.out.println("睡觉啦!!");
return method.invoke(p, args);
}else{
System.out.println("呀呀呀 不做啦");
}
return null;
}
});
}
}
个人总结:
主要学习了静态导入,装拆箱,可变参数,枚举,for循环增强,反射,泛型,注解,代理等知识,内容很多,如果简单的使用,很容易上手,但是认真学习他们的细节,就没那么容易。掌握了这些细节,对于我们开发,阅读其他的程序都是非常有帮助的。