黑马程序员——java高新---JDK1.5新特性和反射
一、JDK1.5新特性
——>静态导入
import和import static之间的区别:
1、import是导入一个类或某个包中所有的类。
2、import static是导入一个类中的某个静态成员或所有的静态成员。
注意:
1、当导入的两个类中有同名成员时,需要在成员前加上相应的类名。
2、当类名重名时,需要指定具体的包名。
3、方法重名时,需要指定具体所属的对象或者类。
代码示例:
1 import java.util.*;//导入了Util包中所有的类 2 import static java.util.Arrays.*;//导入leArrays这个类中的所有静态成员。 3 import static java.util.Collections.sort;//导入了Collections类中的sort方法。 4 import static java.lang.System.out;//导入了System类中的out。 5 class StaticImport {
6 7 public static void main(String[] args){
8 9 out.println("abc");//省略了System. 10 int[] arr = {3,1,5}; 11 sort(arr); 12 out.println(Arrays.toString(arr)); 13 //这里的Arrays不能省略,因为该类默认继承了Object类,而Object类也有toString方法,当方法重名时,指定具备所属的类 14 ArrayList al = new ArrayList(); 15 al.add(1); 16 al.add(3); 17 al.add(2); 18 out.println(al); 19 sort(al); 20 out.println(al); 21 } 22 }
——>可变参数
概念:函数的另一种表现形式。
格式:
返回值类型 函数名(参数类型 ... 形式参数) {
执行语句;
}
其实接收的是一个数组,可以实际调用时指定可变的参数个数。
注意:
1、可变参数只能出现在参数列表的最后。
2、 ...位于变量类型和变量名之间,前后有无空格都可以。
3、调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。
代码示例:
1 public class TestVariableParameter { 2 3 public static void main(String[] args) { 4 show(2, 3, 4, 5, 6, 8); 5 show2("haha..."); 6 } 7 8 public static void show(int x, int... args) { 9 // 执行语句 10 int sum = x; 11 for (int i = 0; i < args.length; i++) { 12 sum = sum + args[i]; 13 } 14 System.out.println(sum); 15 } 16 17 public static void show2(String... args) { 18 String newStr = ""; 19 for (int i = 0; i < args.length; i++) { 20 newStr = newStr + args[i]; 21 } 22 System.out.println(newStr); 23 } 24 25 }
——>增强型for循环
格式:
for(数据类型 变量名 : 被遍历的集合(collection)或者数组) {
执行语句;
}
说明:
1、对集合进行遍历。只能获取集合元素。但是不能对集合进行操作。可以看作是迭代器的简写形式。
2、迭代器除了遍历,还可以进行remove集合中元素的动作。如果使用ListIterator,还可以在遍历过程中对集合进行增、删、改、查的操作。
3、增强型for循环的变量类型前可加修饰符,如final(可被局部内部类访问到)。
传统for循环和增强for循环的区别:
1、传统for循环可以完成对语句的多次操作,因为可以控制循环增量条件。在遍历数组时有角标索引。
2、高级for循环是一种简化形式,它必须有遍历目标,该目标要么是array或Collection单列集合,不可以直接遍历Map集合,但可以将Map集
合转化为单列的Set集合,就可以使用。例如:
代码示例:
1 for(Map.Entry<Integer,String>) me : map.entrySet()){ 2 Integer key = me.getKey(); 3 String value = me.getValue(); 4 System.out.println(key + ":" + value); 5 6 }
——>枚举的高级应用
枚举:就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。
枚举元素:必须位于枚举体中的最开始部分,枚举元素列表的后要有分号与其他成员分隔。把枚举中的成员方法或变量等放在枚举元素的前面,编
译器报告错误。
带构造方法的枚举:
1、构造方法必须定义成“私有“。
2、枚举元素MON和MON()的效果一样,都是调用默认的构造方法。
带方法的枚举:
1、定义枚举TrafficLamp
2、实现普通的next方法
3、实现抽象的next方法:每个元素分别是由枚举类的子类来生成的实例对象,这些子类采用类似内部类的方式进行定义。
4、增加表示时间的构造方法
代码示例:
1 public class TestEnum { 2 3 public enum TrafficLamp { 4 RED(30) { 5 public TrafficLamp nextLamp() { 6 return GREEN; 7 } 8 }, 9 10 GREEN(30) { 11 public TrafficLamp nextLamp() { 12 return YELLOW; 13 } 14 }, 15 16 YELLOW(5) { 17 public TrafficLamp nextLamp() { 18 return RED; 19 } 20 }; 21 22 private int time; 23 24 // 构造器 25 private TrafficLamp(int time) { 26 this.time = time; 27 } 28 29 // 抽象方法 30 public abstract TrafficLamp nextLamp(); 31 } 32 33 }
二、反射
Java反射机制:是指“在运行状态中”,对于任意一个类,都能够知道这个类中的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方
法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Java反射机制主要提供了以下功能:
1、在运行时,判断任意一个对象所属的类
2、在运行时,构造任意一个类的对象
3、在运行时,判断任意一个类所具有的成员变量和方法(通过反射实现)。
4、在运行时,调用任意一个对象的方法(注意:前提都是在运行时,不是在编译时)
实质:是对类进行解剖,将Java类中的各种构成成分映射成相应的java类。
一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的Java类来表示。表示
java类的Class类提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等,这些信息就是用相应类的实例对象来表示,它们是Field、
Method、Contructor、Package等。
作用:实现框架功能
△ 框架:通过反射调用Java类的一种方式。框架如同地产商建造房子,门窗和空调等等内部装修都由用户自己安装。房子就是框架,用户需
使用此框架,安好门窗等放入到房地产商提供的框架中。
△ 注意:框架和工具类的区别在于工具类被用户类调用,而框架是调用用户提供的类。
△ 框架要解决的核心问题:我们在写框架的时候,调用的类还未出现,那么框架无法知道要被调用的类名,所以在程序中无法直接new某个类
的实例对象,而要通过反射来做。
——>class类: 反射的基石
概述:Java程序中的各个Java类属于同一类事物,可以用一个类来描述这类事物,就是Class。Class类代表Java类,它的各个实例对象又分别对应
各个类在内存中的字节码,一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,
所以它们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来表示。学习反射,首先就要明白Class这个类。每个java类都是Class的一个实例对象。
——>Class和class的区别:
1、class:Java中的类用于描述一类事物的共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则由此类的实例对象确
定,不同的实例对象有不同的属性值。
2、Class:指的是Java程序中的各个Java类是属于同一类事物,都是Java程序的类,这些类称为Class。Class是Java程序中各个Java类的总
称;它是反射的基石,通过Class类来使用反射。
得到字节码的三种方式:
1、类名.class,例如,System.class
2、对象.getClass(),例如,new Date().getClass()
3、Class.forName("类名"),例如,Class.forName("java.util.Date");
注意:Class.forName()返回字节码的方式有两种,第一种是这份字节码曾经被加载过,已经存在于虚拟机中,直接返回。还有一种是java虚拟机中
还没有这份字节码,则用类加载器去加载,把加载进来的字节码缓存在虚拟机中以后要得到这份字节码就不用再加载了。
九种预定义的Class:
包括八种基本类型(byte、short、int、long、float、double、char、boolean)的字节码对象和一种返回值为void类型的void.class 。
注意:基本类型的字节码和包装类的字节码不一样,例如,int.class 和Integer.class 对应的字节码不一样。但是,Integer.TYPE表示此包装类型
包装的基本类型的字节码,所以int.class 和Integer.TYPE是一致的。9个预定义类型都是如此。
Class类中常用的方法:
forName(String className):返回与给定字符串名的类或接口的相关联的Class对象。
getClass():返回的是Object运行时的类,即返回Class对象即字节码对象。
getConstructor():返回Constructor对象,它反映此Class对象所表示的类的指定公共构造方法。
getField(String name):返回一个Field对象,它表示此Class对象所代表的类或接口的指定公共成员字段。
getFields():返回包含某些Field对象的数组,表示所代表类中的成员字段。
getMethod(String name,Class… parameterTypes):返回一个Method对象,它表示的是此Class对象所代表的类的指定公共成员方法。
getMehtods():返回一个包含某些Method对象的数组,是所代表的的类中的公共成员方法。
getName():以String形式返回此Class对象所表示的实体名称。
getSuperclass():返回此Class所表示的类的超类的名称。
isArray():判定此Class对象是否表示一个数组。
isPrimitive():判断指定的Class对象是否是一个基本类型。
newInstance():创建此Class对象所表示的类的一个新实例。
代码示例:
1 public class Person { 2 private int age; 3 public String name; 4 5 public Person() { 6 System.out.println("person"); 7 } 8 private Person(String name, int age) { 9 this.name = name; 10 this.age = age; 11 System.out.println(name+";"+age); 12 } 13 public void run(){ 14 System.out.println("run"); 15 } 16 private void run(String name){ 17 System.out.println(name+" run"); 18 } 19 public static void run1(){ 20 System.out.println("run1"); 21 } 22 public static void main(String[] args) { 23 System.out.println("main"); 24 for(String string:args){ 25 System.out.println(string); 26 } 27 } 28 }
——>Constructor类
概念:Constructor代表某个类的一个构造方法。
构造方法:
1、得到这个类的所有构造方法:例如:Constructor[] cons = Class.forName (“java.lang.String”) . getConstructors ();
2、得到某一个构造方法:Constructor con = String.class.getConstructor (String.class , int.class);
创建实例对象:
1、通常方式:String str = new String ( new StringBuffer(“abc”));
2、反射方式:String str = (String) constructor.newInstance ( new StringBuffer (“abc”));
注意:
1、创建实例时newInstance方法中的参数列表必须与获取Constructor的方法getConstructor方法中的参数列表一致。
2、newInstance():构造出一个实例对象,每调用一次就构造一个对象。
3、利用Constructor类来创建类实例的好处是可以指定构造函数,而Class类只能利用无参构造函数创建类实例对象。
示例代码:
1 //得到公有空参数构造方法 2 public void test1() throws Exception{ 3 Class clazz=Class.forName("cn.itcast.reflect.Person"); 4 Constructor con= clazz.getConstructor(null); 5 Person p1=(Person) con.newInstance(null); 6 System.out.println(p1); 7 } 8 //得到私有对应参数构造方法 9 public void test2() throws Exception{ 10 Class clazz=Class.forName("cn.itcast.reflect.Person"); 11 Constructor con= clazz.getDeclaredConstructor(String.class,int.class);//可以得到私有的构造方法 12 //暴力反射,打开私有构造方法的权限 13 con.setAccessible(true); 14 Person p1=(Person) con.newInstance("zs",20); 15 System.out.println(p1); 16 }
——>Field类
概念:Field类代表某个类中一个成员变量
方法:
getField(String s):只能获取公有和父类中公有
getDeclaredField(String s):获取该类中任意成员变量,包括私有
setAccessible(ture)://如果是私有字段,要先将该私有字段进行取消权限检查的能力。也称暴力访问。
set(Object obj, Object value):将指定对象变量上此Field对象表示的字段设置为指定的新值。
get(Object obj):返回指定对象上Field表示的字段的值。
示例代码:
1 //得到公有字段 2 public void test3() throws Exception{ 3 Person p=new Person(); 4 Class clazz=Class.forName("cn.itcast.reflect.Person"); 5 Field field=clazz.getField("name"); 6 System.out.println(p.name); 7 field.set(p, "abc"); 8 System.out.println(p.name); 9 } 10 11 //得到私有字段 12 public void test4() throws Exception{ 13 Person p=new Person(); 14 Class clazz=Class.forName("cn.itcast.reflect.Person"); 15 Field field=clazz.getDeclaredField("age"); 16 field.setAccessible(true); 17 field.set(p, 20); 18 System.out.println(field.get(p)); 19 }
——>Method类
概念:Method类代表某个类中成员方法。调用某个对象身上的方法,要先得到方法,再针对某个对象调用。
方法:
getMethods():只获取公共和父类中的方法。
getDeclaredMethods():获取本类中包含私有。
getMethod("方法名",参数.class(如果是空参可以写null));
invoke(Object obj ,参数):调用方法
注意:invoke方法:如果底层是静态的,那么可以忽略指定的obj参数,填充为null。② 如果底层方法所需的“形式参数”为0,则所提供的args数组长
度可以为0或null。
获取类中方法:
1、通常方式:对象名.函数。如str.charAt(int index);
2、反射方式:
Method MethodCharAt = Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);
3、反射调用底层方法:charAtMethod.invoke(str, int index);
说明:如果传递给Method对象的invoke()方法的第一个参数为null,说明Method对象对应的是一个静态方法
代码示例:
1 //得到公有非静态方法 2 public void test5() throws Exception{ 3 Person p=new Person(); 4 Class clazz=Class.forName("cn.itcast.reflect.Person"); 5 Method method=clazz.getMethod("run", null); 6 method.invoke(p, null); 7 } 8 9 //得到私有非静态方法 10 public void test6() throws Exception{ 11 Person p=new Person(); 12 Class clazz=Class.forName("cn.itcast.reflect.Person"); 13 Method method=clazz.getDeclaredMethod("run", String.class); 14 method.setAccessible(true); 15 method.invoke(p, "zcg"); 16 } 17 18 //得到公有静态方法 19 public void test7() throws Exception{ 20 Class clazz=Class.forName("cn.itcast.reflect.Person"); 21 Method method=clazz.getMethod("run1", null); 22 method.invoke(null, null); 23 } 24 25 //得到主函数 26 public void test8() throws Exception{ 27 Person p=new Person(); 28 Class clazz=Class.forName("cn.itcast.reflect.Person"); 29 Method mainMethod=clazz.getMethod("main", String[].class); 30 mainMethod.invoke(null, new Object[]{new String[]{"aa","bb"}}); 31 mainMethod.invoke(null, (Object)new String[]{"aa","bb"}); 32 33 }
——>数组的反射
具有相同维数并且相同元素类型的数组属于同一个类型,即具有相同的Class实例对象(此处比较与值无关)。Array工具类用于完成对数组的反射操作。
int[] a1 = new int[]{2,5,7};
int[] a2 = new int[4];
int[][] a3 = new int[3][5];
String[] a4 = new String[]{"d","j","f"};
所有一维数组的父类都是Object,基本数据类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本数据类型的一维数
组,既可以当做Object类型使用,又可以当做Object[]类型使用。二维数组可以看作Object类型,也可以看做Object[]。也就是说,整个一维数组、二
维数组中的数组都可以看做Object类型。例如,a1、a3的元素、a4的元素都是Object。另外,引用数据的数组既可以当做Object,也可以当做
Object[]。
Arrays的asList()方法在处理基本类型数组(int[])和引用类型数组(String[])时的差异:传入引用数据的数组将变成集合,数组中的元素变成集合中
的元素;传入的基本数据的数组会变成一个Object对象。因为JDK1.4中,asList()接受的是数组Object[];JDK1.5中,asList()接受的是可变参数T…
a,T可以是基本型或引用型。JDK1.5需要向下兼JDK1.4。a4会按照1.4处理,直接打印数组内容;a1会按照1.5处理,打印出哈希值。想要打印基本
数据的数组,可以逐个元素录入,或者使用反射中的Array工具类对数组进行反射操作。Class中拥有Arrays没有的方法,例如判断对象所属的类是否是
数组等,再用Array中的方法操作数组。这些方法基本是静态方法,需要将数组对象传入。例如,打印对象,类似拆包。
代码示例:
1 import java.lang.reflect.Array; 2 import java.util.Arrays; 3 public class ArrayReflect { 4 public static void main(String[] args) { 5 int [] a1 = new int[]{1,2,3}; 6 int[][] a2 = new int[2][3]; 7 String [] a3 = new String[]{"a","b","c"}; 8 Object obj1 = a1; 9 Object obj2 = a3; 10 Object obj3 = a4; 11 //Array工具类用于完成对数组的反射操作。如打印任意数值 12 printObject(a1); 13 printObject(a4); 14 printObject("abc"); 15 } 16 //打印任意数值 17 private static void printObject(Object obj) { 18 Class clazz = obj.getClass(); 19 //如果传入的是数组,则遍历 20 if(clazz.isArray()){ 21 int len = Array.getLength(obj);//Array工具类获取数组长度方法 22 for(int x = 0;x<len;x++){ 23 System.out.println(Array.get(obj, x));//Array工具获取数组元素 24 } 25 } 26 else 27 System.out.println(obj); 28 } 29 }