javase_18(回顾与反射机制学习)
AM上午总结:
1 package com.java.kudy.day17_2.ObjectReview; 2 3 public class ObjectTest { 4 5 /** 6 *虚拟机做了什么事情? 7 *1.在栈内存中定义了一个变量p 8 *2.在类加载器中加载Person.class 9 *3.在堆内存中开辟空间,分配了一个物理地址 10 *4.初始化成员变量,如果没有初始值,那么虚拟机会自动初始化,所有的引用数据类型都为null 11 *5.调用构造函数,为成员赋值(field) 12 *6.将对象的首地址给变量p2 13 */ 14 public static void main(String[] args) 15 { 16 Person p = new Person("小细",18); 17 18 } 19 } 20 21 class Person 22 { 23 private String name; 24 private int age; 25 public Person(){} 26 public Person(String name,int age) 27 { 28 this.name = name; 29 this.age = age; 30 } 31 32 @Override 33 public String toString() 34 { 35 return name+"~"+age; 36 } 37 }
抽象类的回顾:
1 package com.java.kudy.day17_2.Extends; 2 3 public class ExtendsTest { 4 /* 5 * 抽象类: 6 * 1.用abstract修饰的类叫做抽象类 7 * 2.如果该类有抽象的方法,这个类必须要定义成抽象类 8 * 3.抽象类是更好的为了多态而服务,我们在设计软件的时,会有一些列类都具备相同的功能,这时方法一样的声明,即使是方法也可以复用. 9 * 我们应该抽象出一个抽象的父类,方便别人学习软件,也能实现一部分代码.说白了就是:更好的为了多态而服务. 10 * 4.继续抽象类需要实现抽象方法,或者把继承过来的类定义成抽象类. 11 */ 12 public static void main(String[] args) { 13 14 } 15 16 } 17 18 abstract class Student 19 { 20 public abstract void run(); 21 }
接口和内部类的简单复习:
1 package com.java.kudy.day17_2.Extends; 2 3 /* 4 * 接口:一种特殊的抽象类,所有的方法都是抽象的. 5 * 1.实现接口用关键字:implements.可以实现多个接口,接口继承接口可以使用extends 关键字 6 * 2.接口中的所有的方法默认为:public abstractor 共同修饰,所以不需要另外声明 7 * 3.接口中所有的变量默认为常量:public static final所修饰,不需要声明(一份) 8 * 9 * 匿名内部类实现: 10 * new fulei(){ 11 * //内部类的定义 12 * }; 13 * final关键字: 14 * 1.修饰变量成常量. 15 * 2.修饰类不能被继承. 16 * 3.修饰方法不能被重写. 17 */ 18 public class InterfacesTest { 19 20 21 public static void main(String[] args) { 22 Teacher kudy = new Teacher(){ 23 @Override 24 public void teching() { 25 System.out.println("同学们,其实我什么也不懂~~!"); 26 } 27 //匿名内部类实现 28 29 }; 30 } 31 32 } 33 34 interface Teacher 35 { 36 void teching(); //public abstract void teching(); 37 } 38 39 40 package com.java.kudy.day17_2.Extends; 41 42 public class ExtendsDemo { 43 /*使用extends关键字,让子类继承父类 44 * 1.子类会自动复用于父类的方法 45 * 2.可以把一个子类的实例当做父类来使用,调用方法时,是调用子类的方法(多态),但必须是重写了父类的方法,不过可以转型.访问属性是访问父类的 46 * (静态绑定,-->在编译的期间就已经完成了变量的绑定)而访问方法是访问子类的(动态的绑定-->) 47 * 如果是调用子类特有的方法,需要强制转换成子类的类型. 48 * 假设:A的父类是B B的父类的C --> 如果父类型的C 引用指向子类型的对象-->A 49 * 但我想使用B类型的方法,我们只需要把B b = (B)c;强制转换就可以.因为c对象本来就是A. 50 * 3.子类的实例化: 子类在实例化过程中一定调用父类的构造方法,我们在子类的构造函数的第一行可以用this(实参)调用自己的其他方法, 51 * Super(实参)调用父类的某个构造方法,如果第一行什么也不写.默认super()调用父类的不带参数的构造方法 52 * 4子类覆盖父类的方法: 方法名相同,参数类型相同.方法的返回值也必须要相同. 53 * 54 */ 55 public static void main(String[] args) { 56 C c = new A(); 57 //如果我想调用b的方法,原因: 我是你A的父类 58 B b = (B)c; 59 b.run(); 60 b.happy(); 61 } 62 63 } 64 class C 65 { 66 public void run() 67 { 68 System.out.println("a"); 69 } 70 } 71 72 class B extends C 73 { 74 public void run() 75 { 76 System.out.println("b"); 77 } 78 public void happy() 79 { 80 System.out.println("我是happy达人"); 81 } 82 } 83 84 class A extends B 85 { 86 public void run() 87 { 88 super.run(); 89 System.out.println("c"); 90 } 91 }
ArrayList(元素有序,底层数组实现.)
1 package com.java.kudy.day17_2.CollectionTest; 2 3 import java.util.ArrayList; 4 import java.util.Iterator; 5 6 import com.java.kudy.day17_2.reflectDemo.Person; 7 8 public class ArrayListTest { 9 10 public static void main(String[] args) 11 { 12 ArrayList<Person> al = new ArrayList<Person>(); 13 al.add(new Person("a",1)); 14 al.add(new Person("b",2)); 15 al.add(new Person("c",3)); 16 al.add(new Person("d",4)); 17 al.add(new Person("e",5)); 18 19 /* 20 * 迭代的三种方式: 21 */ 22 Iterator<Person> it = al.iterator(); 23 while(it.hasNext()) 24 { 25 Person p = it.next(); 26 System.out.println(p); 27 } 28 29 for(Person p : al) 30 System.out.println(p); 31 32 for(int i=0; i<al.size(); i++) 33 { 34 System.out.println(al.get(i)); 35 } 36 } 37 38 } 39 40 package com.java.kudy.day17_2.CollectionTest; 41 42 import java.util.HashSet; 43 44 import com.java.kudy.day17_2.reflectDemo.Person; 45 46 public class HashSetTest { 47 /* 48 * 通过哈希算法保证元素没重复性 49 * 首先通过哈希算法比较,再用equals比较. 50 * 1.hashCode 51 * 2.equals 52 */ 53 public static void main(String[]args) 54 { 55 HashSet<Person> al = new HashSet<Person>(); 56 al.add(new Person("a",1)); 57 al.add(new Person("b",2)); 58 al.add(new Person("c",3)); 59 al.add(new Person("d",4)); 60 al.add(new Person("a",1)); 61 62 for(Person p : al) 63 System.out.println(p); 64 } 65 }
TreeSet:可以写比较器..(如果没有实现接口的方法,会出异常信息)
1 package com.java.kudy.day17_2.CollectionTest; 2 3 import java.util.Comparator; 4 import java.util.TreeSet; 5 6 import com.java.kudy.day17_2.reflectDemo.Person; 7 8 public class TreeSetTest { 9 public static void main(String[]args) 10 { 11 TreeSet<Person> ts = new TreeSet<Person>(new Comparator<Person>(){ 12 13 @Override 14 public int compare(Person s1, Person s2) { 15 int num = s1.getAge()-s2.getAge(); 16 if(num!=0) 17 return num; 18 return s1.getName().compareTo(s2.getName()); 19 } 20 21 }); 22 ts.add(new Person("a",1)); 23 ts.add(new Person("b",2)); 24 ts.add(new Person("c",3)); 25 ts.add(new Person("d",4)); 26 ts.add(new Person("a",1)); 27 for(Person p :ts) 28 System.out.println(p); 29 } 30 }
Map回顾练习:
1 package com.java.kudy.day17_2.CollectionTest; 2 3 import java.util.HashMap; 4 import java.util.Iterator; 5 import java.util.Map.Entry; 6 import java.util.Set; 7 8 public class HashMapTest { 9 10 /** 11 * @param args 12 */ 13 public static void main(String[] args) 14 { 15 HashMap<Teacher, Integer> hm = 16 new HashMap<Teacher, Integer>(); 17 hm.put(new Teacher("a",1), 1); 18 hm.put(new Teacher("a",1), 1); 19 hm.put(new Teacher("b",2), 1); 20 hm.put(new Teacher("c",3), 1); 21 //保证了key的无重复性 22 23 /* //方式一: 24 Set<Entry<Teacher, Integer>> entrys = hm.entrySet(); //获取一个试图 25 Iterator<Entry<Teacher, Integer>> it = entrys.iterator(); 26 while(it.hasNext()) 27 { 28 Entry<Teacher, Integer> e = it.next(); //迭代器,迭代下一个内容 29 Teacher key = e.getKey(); 30 Integer value = e.getValue(); 31 System.out.println(key +"--"+value); 32 }*/ 33 34 //方式二: 35 Set<Teacher> keys= hm.keySet(); 36 for(Teacher t : keys) 37 { 38 Integer value = hm.get(t); 39 System.out.println(t+"--"+value); 40 } 41 42 } 43 44 }
Properties的应用:
1 package com.java.kudy.day17_2.CollectionTest; 2 3 import java.io.FileNotFoundException; 4 import java.io.FileReader; 5 import java.io.IOException; 6 import java.io.PrintStream; 7 import java.util.Enumeration; 8 import java.util.Properties; 9 10 public class PropertiesTest { 11 12 /** 13 * @param args 14 * 用于读写配置文件 15 * @throws IOException 16 * @throws FileNotFoundException 17 */ 18 public static void main(String[] args) throws FileNotFoundException, IOException { 19 Properties prop = new Properties(); 20 prop.load(new FileReader("src/a.properties")); //读取进来 21 Enumeration e = prop.propertyNames(); 22 23 //通过枚举获取到键-->值 24 while(e.hasMoreElements()) 25 { 26 String key = (String)e.nextElement(); 27 String value = prop.getProperty(key); 28 System.out.println(key+"----"+value); 29 } 30 31 // 调用 Hashtable 的方法 put 键和值进来 key value 32 prop.setProperty("name","my_kudy"); 33 prop.setProperty("age", "19"); 34 //直接把内容打印到一个配置文件里面去 35 prop.list(new PrintStream("src/a.properties")); //直接把字节和字符写入进去 36 //把内容输入里面去 37 } 38 39 }
PM下午总结:
JAVA语言中的反射机制:
在Java 运行时 环境中,对于任意一个类,能否知道这个类有哪些属性和方法?
对于任意一个对象,能否调用他的方法?这些答案是肯定的,这种动态获取类的信息,以及动态调用类的方法的功能来源于JAVA的反射。从而使java具有动态语言的特性。
JAVA反射机制主要提供了以下功能:
1.在运行时判断任意一个对象所属的类
2.在运行时构造任意一个类的对象
3.在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法)
4.在运行时调用任意一个对象的方法(*****注意:前提都是在运行时,而不是在编译时)
Java 反射相关的API简介:
位于java。lang。reflect包中
--Class类:代表一个类
--Filed类:代表类的成员变量
--Method类:代表类的方法
--Constructor类:代表类的构造方法
--Array类:提供了动态创建数组,以及访问数组的元素的静态方法。该类中的所有方法都是静态方法
----Class类
在 java 的Object类中的申明了数个应该在所有的java类中被改写的methods:
hashCode(), equals(),clone(),toString(),getClass()等,其中的getClass()返回yige
Class 类型的对象。
Class类十分的特殊,它和一般的类一样继承自Object,其实体用以表达java程序运行
时的 class和 interface,也用来表达 enum,array,primitive,Java Types 以及关键字void
,当加载一个类,或者当加载器(class loader)的defineClass()被JVM调用,便产生一个Class
对象,
Class是Reflection起源,针对任何你想探勘的class(类),唯有现为他产生一个Class
的对象,接下来才能经由后者唤起为数十多个的反射API。
Java允许我们从多种途径为一个类class生成对应的Class对象。
--运用 getClass():Object类中的方法,每个类都拥有此方法
String str="abc";
Class cl=str.getClass();
--运用 Class。getSuperclass():Class类中的方法,返回该Class的父类的Class
--运用 Class。forName()静态方法:
--运用 ,Class:类名.class
--运用primitive wrapper classes的TYPE语法: 基本类型包装类的TYPE,如:Integer.TYPE
注意:TYPE的使用,只适合原生(基本)数据类型
----运行时生成instance
想生成对象的实体,在反射动态机制中有两种方法,一个针对无变量的构造方法,一个针对带参数的
构造方法,,如果想调用带参数的构造方法,就比较的麻烦,不能直接调用Class类中的newInstance()
,而是调用Constructor类中newInstance()方法,首先准备一个Class[]作为Constructor的参数类型。
然后调用该Class对象的getConstructor()方法获得一个专属的Constructor的对象,最后再准备一个
Object[]作为Constructor对象昂的newInstance()方法的实参。
在这里需要说明的是 只有两个类拥有newInstance()方法,分别是Class类和Constructor类
Class类中的newInstance()方法是不带参数的,而Constructro类中的newInstance()方法是带参数的
需要提供必要的参数。
1 package com.java.kudy.day17_2.reflectDemo; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Field; 5 import java.lang.reflect.InvocationTargetException; 6 import java.lang.reflect.Method; 7 import java.lang.reflect.Modifier; 8 9 public class ClassTest { 10 11 /** 12 * @param args 13 * 反射的引用: 14 * ----Class类 15 在 java 的Object类中的申明了数个应该在所有的java类中被改写的methods: 16 hashCode(), equals(),clone(),toString(),getClass()等,其中的getClass()返回一个 17 Class 类型的对象。 18 Class类十分的特殊,它和一般的类一样继承自Object,其实体用以表达java程序运行 19 时的 class和 interface,也用来表达 enum,array,primitive,Java Types 以及关键字void 20 ,当加载一个类,或者当加载器(class loader)的defineClass()被JVM调用,便产生一个Class 21 对象, 22 Class是Reflection起源,针对任何你想探勘的class(类),唯有现为他产生一个Class 23 的对象,接下来才能经由后者唤起为数十多个的反射API。 24 的类 25 * @throws ClassNotFoundException 26 * @throws NoSuchFieldException 27 * @throws SecurityException 28 * @throws IllegalAccessException 29 * @throws IllegalArgumentException 30 * @throws NoSuchMethodException 31 * @throws InvocationTargetException 32 * @throws InstantiationException 33 */ 34 public static void main(String[] args) throws ClassNotFoundException, 35 SecurityException, NoSuchFieldException, 36 IllegalArgumentException, IllegalAccessException, 37 NoSuchMethodException, InvocationTargetException, 38 InstantiationException 39 { 40 Object obj = new Person(); 41 42 //获取实例三中方法 43 //通过对象.getClass获取到运行时的类 44 Class clazz1 = obj.getClass(); //获取到一个类 45 System.out.println(clazz1.getName()); 46 Class clazz2 = Person.class; 47 System.out.println(clazz2.getName()); 48 String className = "com.java.kudy.day17_2.reflectDemo.Person"; 49 Class clazz3 = Class.forName(className); 50 System.out.println(clazz3.getName()); 51 Class clazz4 = int.class; 52 System.out.println(clazz4.getName()); //我们已经映射出一个类 53 54 //获取到一个类中所有的属性(成员属性-->字段) 55 Class clazz = Person.class; 56 Field[] fields = clazz.getDeclaredFields(); 57 58 //遍历,.获取每一个成员属性 59 for(Field field : fields) 60 { 61 /* 62 * 基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double) 63 * 和关键字 void 也表示为 Class 对象-->所以我们返回它的父类的正确的 64 */ 65 String name = field.getName(); //字段名 66 String type = field.getType().getName(); //类型 67 System.out.println("类型:"+type+"字段名:"+name); 68 } 69 /* 70 //获取一个obj对象name的属性,并且改变name属性的值 71 Field declareField = clazz.getDeclaredField("name"); //必须要知道一个字段的名字 72 declareField.setAccessible(true); //编译检查去掉-->private-->public 73 Object value = declareField.get(obj); //获取这个对象字段的值 74 System.out.println(value); //其实这个是打印了对象的toString方法 75 //如果底层字段的类型为基本类型,则对新值进行自动解包 76 declareField.set(obj,"kudy"); //异常信息:有可能底层是不能被访问的 77 Object oj = declareField.get(obj); //返回该字段的值,返回的是object 其实是String类型 78 System.out.println(oj.toString());*/ 79 80 /* 81 * 获取一个类中定义的所有方法 82 */ 83 Method[] methods = clazz.getDeclaredMethods(); 84 for(Method method : methods) 85 { 86 //1.获取到一个方法的名称 87 String name = method.getName(); 88 //2.获取到一个方法的修饰符 89 System.out.print(name+"\t"); 90 int num = method.getModifiers(); 91 if(Modifier.isPublic(num)) 92 System.out.print("public\t"); 93 if(Modifier.isPrivate(num)) 94 System.out.print("Private\t"); 95 if(Modifier.isAbstract(num)) 96 System.out.print("abstractor\t"); 97 //3.获取到形参类型 98 Class[] parameterTypes = method.getParameterTypes(); 99 for(Class type : parameterTypes) 100 System.out.print(type.getName()+"\t"); 101 102 //4.获取到一个返回值类型 103 Class returnType = method.getReturnType(); //返回一个返回值类型 void 104 System.out.println(returnType.getName()); 105 System.out.println(); 106 } 107 /* 108 * 调用obj的setName方法将名字更改成王五 109 110 Method method =clazz.getDeclaredMethod("setName",String.class); 111 method.setAccessible(true);//去掉安全的检查 112 method.invoke(obj, "my_kudy"); 113 System.out.println(obj.toString()); 114 */ 115 116 //获得类中定义的构造方法 117 Constructor[] constructors = clazz.getDeclaredConstructors(); 118 for(Constructor constructor : constructors) 119 { 120 String name = constructor.getName(); 121 System.out.println("构造方法名为:"+name); 122 Class[] types = constructor.getParameterTypes(); 123 System.out.println("参数类型为:"); 124 for(Class type : types) 125 System.out.print(type.getName()+" "); 126 System.out.println(); 127 } 128 129 //调用有参的构造方法,创建对象 130 //Class cz = String.class 131 /* Constructor constructor = 132 clazz.getDeclaredConstructor(String.class,int.class);*/ 133 //基本参数和引用参数都要进行方法调用转换。 134 Constructor constructor = 135 clazz.getDeclaredConstructor(new Class[]{String.class,int.class}); 136 Person p =(Person)constructor.newInstance("小细",19); 137 System.out.println(p); 138 139 //获得包名 140 Package pa = clazz.getPackage(); 141 System.out.println(pa.getName()); 142 143 //获得该类或接口的修饰符 144 int mod = clazz.getModifiers(); 145 if(Modifier.isPublic(mod)) 146 System.out.println("public修饰"); 147 if(Modifier.isAbstract(mod)) 148 System.out.println("Abstractor修饰"); 149 } 150 151 }
面向接口编程思想:
接口:
1 package com.java.kudy.day17_2.GraphDemo; 2 3 public interface GetGraph { 4 5 Double getArea(); 6 7 } 8 Round.class 9 package com.java.kudy.day17_2.GraphDemo; 10 11 public class Round implements GetGraph{ 12 13 private double r; 14 @Override 15 public Double getArea() { 16 return Math.PI*r*r; 17 } 18 19 } 20 21 Test类: 22 package com.java.kudy.day17_2.GraphDemo; 23 24 import java.io.BufferedReader; 25 import java.io.IOException; 26 import java.io.InputStreamReader; 27 import java.lang.reflect.Field; 28 29 public class Test { 30 31 /** 32 * @param args 33 * @throws IOException 34 * @throws ClassNotFoundException 35 * @throws IllegalAccessException 36 * @throws IllegalArgumentException 37 * @throws InstantiationException 38 */ 39 public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalArgumentException, IllegalAccessException, InstantiationException 40 { 41 BufferedReader br = new 42 BufferedReader(new InputStreamReader(System.in)); 43 System.out.println("请输入你需要实现的图形:"); 44 String className = br.readLine(); 45 //映射出一个圆 46 Class clazz = null; 47 try 48 { 49 clazz = Class.forName("com.java.kudy.day17_2.GraphDemo."+className); 50 }catch(RuntimeException e) 51 { 52 System.out.println("您输入的功能还没有实现!!!,等待更新!!"); 53 return ; 54 } 55 //获取到一个类.为这个类创建对象 56 //获取到的类是Round.class 57 GetGraph g = (GetGraph)clazz.newInstance(); //为这个类创建对象 58 //本来是一个Person类型的引用,现在是Object 59 //Object obj = new Person(); 60 //GetGraph g = (GetGraph) Person(); //如果是继承关系.是可以把它更改一吧. 61 //接口指向实现接口 62 /* 63 * Object obj = new Round(); 64 * (GetGraph) 65 * 接口--> = 实现接口 66 */ 67 Field[] fields = clazz.getDeclaredFields(); 68 //遍历所有的属性,并且为他赋值 field.getName()意思: 获取这个属性的名字 69 for(Field field :fields) 70 { 71 System.out.println("请输入"+field.getName()); //获取到这个属性的名字 72 String value = br.readLine(); 73 field.setAccessible(true);//去掉安全检查 74 Double d = Double.parseDouble(value); 75 field.setDouble(g, d); 76 } 77 double area = g.getArea(); 78 System.out.println(area); 79 } 80 81 }
小小的案例回顾:
1 package com.java.kudy.day17_2.GraphDemo; 2 3 class A { 4 public void run() 5 { 6 System.out.println("A.running"); 7 } 8 } 9 10 class B extends A 11 { 12 public void run() 13 { 14 System.out.println("B.running"); 15 } 16 } 17 18 class C extends B 19 { 20 public void run() 21 { 22 System.out.println("C.running"); 23 } 24 } 25 public class TestExtends 26 { 27 /* 28 * 我父类型的引用指向子类型的对象 29 * 但是我们如果想拿第二个子类指向第一个父类.是不可以的.所以我们必须要把它所指向的类型更改为B 30 */ 31 public static void main(String[]args) 32 { 33 A a = new C(); 34 a.run(); 35 B b =(B)a; 36 b.run(); 37 } 38 } 39 40 41 ------------用面向接口的思想实现一个长方形(要求用到反射.) 42 43 接口: 44 package com.java.kudy.day17_2.CollectionTest; 45 46 public interface GetSRound { 47 48 //实现一个面积 49 double getArea(); 50 } 51 52 实现长方形的方法: 53 package com.java.kudy.day17_2.CollectionTest; 54 55 public class Square implements GetSRound{ 56 private double broder ; 57 58 @Override 59 public double getArea() { 60 return broder*broder; 61 } 62 } 63 64 Test: 65 package com.java.kudy.day17_2.CollectionTest; 66 67 import java.io.BufferedReader; 68 import java.io.IOException; 69 import java.io.InputStreamReader; 70 import java.lang.reflect.Field; 71 72 import com.java.kudy.day17_2.GraphDemo.GetGraph; 73 74 public class Test { 75 76 /** 77 * @param args 78 * 用反射求一个正方形的面积 79 * @throws IOException 80 * @throws ClassNotFoundException 81 * @throws IllegalAccessException 82 * @throws InstantiationException 83 */ 84 public static void main(String[] args) throws IOException, 85 ClassNotFoundException, 86 InstantiationException, 87 IllegalAccessException 88 { 89 90 //字节流转换成字符流 91 BufferedReader br = 92 new BufferedReader(new InputStreamReader(System.in)); 93 System.out.println("请输入你要希望求的图形"); 94 String className = br.readLine(); //获取一个类 95 System.out.println(className); 96 Class clazz = null; 97 try 98 { 99 //获取一个类 100 //Class clazz = Square.class 101 clazz = Class.forName("com.java.kudy.day17_2.CollectionTest."+className); 102 }catch (RuntimeException e) { 103 System.out.println("该功能还没有实现.程序已经退出.."); 104 return; 105 } 106 //为这个类创建对象 107 GetSRound g = (GetSRound)clazz.newInstance(); //接口指向实现接口.由于接口里面的方法已经被实现.所以调用她其实就是调用实现接口里面的方法 108 Field[] fields = clazz.getDeclaredFields(); //遍历成员变量 109 for(Field field : fields) 110 { 111 //遍历所有的成员变量,为属性赋值 112 System.out.println("请输入:"+field.getName()); //获取成员变量名 113 field.setAccessible(true); //去掉私有的检查,因为这个类是私有的就oh啦 114 String str = br.readLine(); 115 Double value = Double.parseDouble(str); 116 field.setDouble(g, value); 117 } 118 double area = g.getArea(); 119 System.out.println(area); 120 } 121 122 }