CLASS类
java类表示一类事物。class类表示java中的类事物。
class类的实例对象对应内存中的一份java字节码。
只要在源程序中出现的类型,都有各自的class实例对象,例如 int[] ,void。
对象实例化的过程:类加载器从硬盘上将对应的字节码加载到内存,复制字节码实例化对象。
有9个预定义的class对象。(8个基本类型+void)
获取class实例的三种方式
public static void main(String[] args) throws ClassNotFoundException { //方式一:实例对象获取 String a = "abc"; Class clazzA = a.getClass(); System.out.println(clazzA.getName()); //方式一:类获取 Class clazzB = String.class; //方式一:类的全名称获取--实际中使用最多 Class clazzC = Class.forName("java.lang.String"); System.out.println(clazzA == clazzB); System.out.println(clazzA == clazzC); System.out.println(clazzA.isPrimitive()); System.out.println(int[].class.isPrimitive()); System.out.println(int.class.isPrimitive()); System.out.println(void.class.isPrimitive()); }
java.lang.String true true false false true true
反射
反射是把一个Java类的各个成分解析成为一个个相应的类。例如:Field,Method,Constructor
反射会造成性能下降。
方法的反射
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //构造方法 Constructor c = String.class.getConstructor(String.class);//构造函数的参数类型 列表 //编译器并不知道是谁的构造方法 String a = (String) c.newInstance("constructor");//参数的实际值,newinstance 调用无参数的构造函数 System.out.println("a is "+ a); //普通方法 Method m = String.class.getMethod("substring", int.class); //普通方法传方法的名字,方法的参数类型列表 String b = "111232ew"; b = (String)m.invoke(b, 3); // invoke 都是在对象上invoke 。方法是类的,但是调用方法,需要通过对象去调用。对象是null的话,说明方法是static的
//面向对象:专家模式,将变量设为私有,那个方法需要操作变量,该方法就是类的 System.out.println("b is "+ b); } a is constructor b is 232ew
属性的反射
public class ReflectPoint { public int x; private int y; public int getX() { return x; } public ReflectPoint(int x, int y) { super(); this.x = x; this.y = y; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } } public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { ReflectPoint point = new ReflectPoint(3,6); Field fieldX = point.getClass().getField("x"); System.out.println(fieldX.get(point)); } 3 public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { ReflectPoint point = new ReflectPoint(3,6); Field fieldX = point.getClass().getField("x"); System.out.println(fieldX.get(point)); //看不到私有变量 Field fieldY = point.getClass().getField("y"); System.out.println(fieldY.get(point)); } Exception in thread "main" java.lang.NoSuchFieldException: y at java.lang.Class.getField(Class.java:1703) at day01.FieldTest.main(FieldTest.java:12) //DeclaredField 可看到私有变量 Field fieldY = point.getClass().getDeclaredField("y"); //设置可获得私有变量 fieldY.setAccessible(true); System.out.println(fieldY.get(point));
数组的反射
类型相同,维度相同的数组,反射都是同一种类型。
Arrays可以处理数组的反射。
//test3 int[] aInt = new int[5]; int[] bInt = new int[5]; int[][] cInt = new int[5][3]; System.out.println(aInt.getClass().getName()); System.out.println(bInt.getClass().getName()); System.out.println(cInt.getClass().getName()); //[ 表示数组,I 表示 int [I [I [[I
//test3 int[] aInt = new int[5]; int[] bInt = new int[5]; int[][] cInt = new int[5][3]; System.out.println(aInt.getClass().getSuperclass().getName()); System.out.println(bInt.getClass().getSuperclass().getName()); System.out.println(cInt.getClass().getSuperclass().getName()); Object aObj = aInt; Object bObj = bInt; Object cObj = cInt; String[] dStr = new String[5]; //Object[] aObjArr = aInt; //报错 Object[] dObjArr = dStr; Object[] cObjArr = cInt; java.lang.Object java.lang.Object java.lang.Object
可变参数
1.只能出现在参数列表的最后一个参数。
2.写法 public void test(int a ,int ... args){}
3.编译器在方法内部,将可变参数处理为数组。
package day01; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class ArrayParamTest { public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //test1 int a1 = 5; Object b1 = a1; int[] a = new int[5]; //Object[] b = a; //报错 ,说明无法判断一个数组的类型,只能知道数组内某个值的类型 //test2 Method m = ArrayParamTest.class.getMethod("testa", String[].class); m.invoke(null, new String[]{"11","33"}); } public static void testa(String[] aa){ System.out.println(aa[0]); } } Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at day01.ArrayParamTest.main(ArrayParamTest.java:18)
package day01; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class ArrayParamTest { public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //test1 int a1 = 5; Object b1 = a1; int[] a = new int[5]; //Object[] b = a; //报错 ,说明无法判断一个数组的类型,只能知道数组内某个值的类型 //test2 Method m = ArrayParamTest.class.getMethod("testa", String[].class); //由于JDK1.5 以后有了可变参数,所以接收可变参数(数组)的方法 可能都有这个问题。 //传数组的话,编译器会进行拆箱。 m.invoke(null, (Object)new String[]{"11","33"}); } public static void testa(String[] aa){ System.out.println(aa[0]); } } 11
注解
注解是一种标记,Java编译器,开发工具和其他应用程序可以通过反射来获取类以及元素上的各种标记,就去干相应的事。
注解可以在包上,类上,字段,方法,方法的参数以及局部变量上。
@ 表示创建一个注解
public @interface AnnotionFirst { public int a() default 5; } @AnnotionFirst public class AnnotionClass { public static void main(String[] args) { AnnotionFirst a = (AnnotionFirst)AnnotionClass.class.getAnnotation(AnnotionFirst.class); System.out.println("a is "+ a); } } a is null
输出null ,说明在运行的时候,AnnotionClass 该类上没有注解。
源注解-- Retention
表示注解应用在哪个阶段。
3个阶段,源码上(source),class文件里(class),字节码(runtime)。编译器编译成class文件的时候,处理掉了一部分注解,类加载器加载class文件为字节码时,也处理了一部分注解。默认使用
RetentionPolicy.CLASS
override是SOURCE阶段
SuppressWarnings是SOURCE阶段
Deprecated是RUNTIME阶段
import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @Retention(RetentionPolicy.RUNTIME) public @interface AnnotionFirst { public int a() default 5; } @AnnotionFirst public class AnnotionClass { public static void main(String[] args) { AnnotionFirst a = (AnnotionFirst)AnnotionClass.class.getAnnotation(AnnotionFirst.class); System.out.println("a is "+ a); } } a is @day01.AnnotionFirst(a=5)
源注解-- Target
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface AnnotionFirst { public int a() default 5; }
target的值可以有 TYPE(类、接口、枚举、注解这一类事物用TYPE表示),
FIELD,METHOD,CONSTRUCTOR,PACKAGE等,具体的看 ElementType 这个枚举。
相应的值就对应相应的位置。
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.TYPE,ElementType.FIELD}) //支持传数组,但是只有一个值的时候,不用写成数组的格式,编译器会自动识别。 public @interface AnnotionFirst { public int a() default 5; }
注解的属性
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.TYPE,ElementType.FIELD}) public @interface AnnotionFirst { //1 int a() default 5; //默认是public的,表示有一个int类型的数据 //2 int value() ; } @AnnotionFirst(4) public class AnnotionClass { public static void main(String[] args) { AnnotionFirst annotion = (AnnotionFirst)AnnotionClass.class.getAnnotation(AnnotionFirst.class); System.out.println("annotion is "+ annotion); System.out.println("annotion-value is "+ annotion.value()); } } annotion is @day01.AnnotionFirst(a=5, value=4) annotion-value is 4
int a() default 5; //默认是public的,表示有一个int类型的数据,其默认值是5
@AnnotionFirst(4) 当只有一个属性名为value的属性需要赋值时,属性名可以省略。
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.TYPE,ElementType.FIELD}) public @interface AnnotionFirst { //1 int a() default 5; //默认是public的,表示有一个int类型的数据 //2 int value() default 3; //3 数组的使用 int[] intArr(); //4 枚举类型的使用 ElementType elementType(); //5注解的使用 AnnotionTwo annotionTwo(); //6 类的使用 Class clazz(); //7组合使用 } package day01; public class AnnotionClass2 { private String a = "i am AnnotionClass2"; public String getA() { return a; } public void setA(String a) { this.a = a; } } package day01; 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.TYPE,ElementType.FIELD}) public @interface AnnotionTwo { int a() default 5; } import java.lang.annotation.ElementType; @AnnotionFirst(intArr=1, elementType = ElementType.TYPE, annotionTwo = @AnnotionTwo(a=8), clazz = AnnotionClass2.class) public class AnnotionClass { public static void main(String[] args) { AnnotionFirst annotion = (AnnotionFirst)AnnotionClass.class.getAnnotation(AnnotionFirst.class); System.out.println("annotion is "+ annotion); System.out.println("annotion-value is "+ annotion.value()); System.out.println("annotion-intArr is "+ annotion.intArr()); System.out.println("annotion-elementType is "+ annotion.elementType()); System.out.println("annotion-annotionTwo-a is "+ annotion.annotionTwo().a()); System.out.println("annotion-clazz is "+ annotion.clazz().getName()); } } annotion is @day01.AnnotionFirst(value=3, a=5, intArr=[1], elementType=TYPE, annotionTwo=@day01.AnnotionTwo(a=8), clazz=class day01.AnnotionClass2) annotion-value is 3 annotion-intArr is [I@14ae5a5 annotion-elementType is TYPE annotion-annotionTwo-a is 8 annotion-clazz is day01.AnnotionClass2
泛型
泛型是提供给编译器看的,编译完成之后,去掉了类型。称为去类型化。
泛型用在集合和反射
demo
import java.util.ArrayList; import java.util.List; public class GenericsTest { public static void main(String[] args) { List<String> strList = new ArrayList<>(); strList.add("aa"); } }
集合使用泛型后,同类型的才能放到一起,同时,不需要进行强制类型转换。
demo
public void iterableMap(Map<String, Object> map) { for (Entry<String, Object> entry: map.entrySet()) { System.out.println("key:"+entry.getKey()+",value:"+entry.getValue()); } }
泛型可以用在反射。
public class GenericsTest { public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { List<String> strList = new ArrayList<>(); strList.add("aa"); Constructor<String> constructor = String.class.getConstructor(String.class); String str = constructor.newInstance("bb"); System.out.println(str); } }
bb
泛型的术语
ArrayList<E> 泛型类型
E 类型参数,变量
ArrayList<String> 参数化的类型 。 ArrayList TYPE OF String
String 实际的参数类型/类型参数的实例
ArrayList 原始类型
参数化类型和原始类型的兼容性:可以互相引用。
参数化类型不考虑 继承关系。
//test3 List str1 = new ArrayList<>(); List<String> str2 = new ArrayList<>(); List<Object> str3 = new ArrayList<>(); str1 = str2; str2 = str1; // str3 = str2; 报错,没有继承关系
通配符?
通配符? ,不能调用与类型有关的方法。
public void add(Collection<?> coll) { System.out.println(coll.size()); //coll.add("s"); 报错 }
使用? 可以指向其他各种参数化的类型。 ? 的主要作用是引用。
//test4 List<String> str4 = new ArrayList<>(); List<?> str5 = new ArrayList<>(); str5 = str4;
? 的扩展
? extends Number :Number 及其子类
? super Number : Number 及其父类
//test5 Vector<? extends Number> x = new Vector<Number>(); Vector<? extends Number> y = new Vector<Integer>(); //Vector<? extends Number> z = new Vector<Object>(); 报错 Vector<? super Number> h = new Vector<Number>(); Vector<? super Number> i = new Vector<Object>(); //Vector<? super Number> z = new Vector<Integer>();报错
泛型的高级应用
java中的泛型类似于C++中的模板方法,仅表面类似。编译成class文件之后,没有泛型。
在方法上的应用:
在返回值之前,用一对尖括号说明类型T。涉及类型的推断。
public <T> void add1(Collection<T> coll,T e) { coll.size(); coll.add(e); }
在类上的应用:
在类上的泛型类型,所有方法都可以使用。除了静态方法。
public class ReflectDao<T> { public long insert(T entity){ System.out.println("insert"); return 1; } public long delete(T entity){ System.out.println("delete"); return 1; } } public static void main(String[] args) { ReflectDao<ReflectPoint> dao = new ReflectDao<ReflectPoint>(); ReflectPoint r = new ReflectPoint(3,4); dao.insert(r); }