规则
覆盖和重载的区别
规则
注意
特点
equals和等号的区别——重点
等号(==)
equals
合理的equals重写逻辑
注意
字符串和基本数据类型的包装类创建的对象存在hashCode相同的情况,因为是由内容导出的
<!--实现-->
public class TestHashCode { public static void main(String[] args) { String s1 = "a"; String s2 = "a"; Integer i = 10; Integer k = 10; System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); System.out.println(s1.equals(s2)); System.out.println(i.hashCode()); System.out.println(k.hashCode()); System.out.println(i.equals(k)); } }/* output 97 97 true 10 10 true */
如果重新定义equals方法,就必须重新定义hashCode方法,以便用户可以将对象插入到散列表中。如果重新定义,会出现equals相等,hashCode不等——考点
<!--equals与hashCode的定义必须一致,两个对象equals为true,就必须有相同的hashCode。反之则不成立。-->
<!--如果定义的equals比较的是雇员ID,那么hashCode就需要散列ID,而不是雇员的姓名或住址-->
注意
toString方法常见的原因:当对象与一个字符串通过操作符+连接,编译将自动使用toString方法
<!--实现-->
public class TestToString { String name = "asd"; public static void main(String[] args) { TestToString testToString = new TestToString(); System.out.println(testToString+"jkl"); } }/* output Five.TestToString.TestToString@1218025cjkl */
建议重写toString方法,默认调用的方法可读性较差
<!--实现-->
public class TestToString { String name = "asd"; @Override public String toString() { return "TestToString{" + "name='" + name + '/'' + '}'; } public static void main(String[] args) { TestToString testToString = new TestToString(); System.out.println(testToString+"jkl"); } }/* output TestToString{name='asd'}jkl */
用途:返回包含对象信息的类对象
<!--实现-->
public class TestToString { String name = "asd"; public static void main(String[] args) { TestToString testToString = new TestToString(); System.out.println(testToString.getClass()); } }/* output class Five.TestToString.TestToString */
定义:采用类型参数的泛型类
<!--实现-->
// 使用方法 ArrayList<Employee> staff = new ArrayList<Employee>(); // 泛型的类型为Employee
规则
注意
装箱 定义:基本数据类型变换为基本类型的包装类
<!--实现-->
// 装箱 public class TestAutoBoxing { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(); list.add(5); // 等于 list.add(Integer.valueOf(5)); } }/* conclusion 1.list中的元素为Integer类型 2.当使用.add()方法添加时,被添加的类型为基本类型int 3.因此将自动变换为 list.add(Integer.valueOf(5)) */
注意
自动装箱规范要求boolean,byte,char小于等于127,介于-128至127之间的short和int被包装到固定的对象中。
原因是:IntegerCache.low 默认是-128;IntegerCache.high默认是127,超出范围的将创建对象存储,不然直接返回值。减少new,减轻jvm压力。
<!--实现-->
public class TestAutoBoxing { public static void main(String[] args) { // 使用包装类 Integer a = 127; Integer b = 127; Integer c = 128; Integer d = 128; System.out.println("a == b:"+(a == b)); System.out.println("c == d:"+(c == d)); } }/* output a == b:true c == d:false */
拆箱 定义:将包装类数据拆成基本类型数据
<!--实现-->
public class TestAutoBoxing { public static void main(String[] args) { // 装箱 ArrayList<Integer> list = new ArrayList<Integer>(); list.add(5); // 拆箱 int intType = list.get(0); // 等于 int intType = list.get(0).intValue(); } }/* conclusion 1.list中的元素为Integer类型 2.当使用.get()方法获取时,获得的值类型为Integer 3.因此将自动变换为 int intType = list.get(0).intValue(); */
格式
// 使用 ... Double ... args
<!--比如System.out.printf()方法,能够接收多个参数-->
// 同时接收多个参数 System.out.printf("%d %s",n,"name"); // 底层实现代码 public PrintStream printf(String format, Object ... args) { return format(format, args); } /* conclusion 1.“String format”为格式字符串,“Object ... args”为Object对象的数组,因此数量可变 */
<!--使用参数可变实现查找最大值-->
public class TestFindMax { static void findMax(Object ... args){ double largest = Double.NEGATIVE_INFINITY; for (Object y: args ) { Double z = (Double) y; if (z > largest) largest = z; } System.out.println(largest); } public static void main(String[] args) { TestFindMax.findMax(3.454,34.3); } }
格式
enum EnumName{ MAX,MIN,DEDIUM; }
注意
枚举类中是实例,因此能够创建实例中的变量,但必须使用构造方法赋值
<!--实现-->
public class TestEnum { public enum Size{ MAX("max",3),MIN("min",1),MEDIUM("medium",2); // 成员变量 private String name; private int num; // 成员变量的构造方法 Size(String name , int i) { this.name = name; this.num = i; } } public static void main(String[] args) { // 在同一个类中,因此可以访问私有的成员变量name String name = Size.MAX.name; System.out.println(name); } }
反射机制:将类中的各个部分封装成其他对象
原理图
Class.forName("全类名"):在第一阶段,将字节码文件加载进内存,然后获取Class对象
多用于配置文件
类名.class:在第二阶段,通过类名的class属性
多用于参数的传递
对象.getClass():在第三阶段,通过Object的getClass方法获取
多用于对象的字节码的获取
<!--实现-->
public class TestReflectionClass { public static void main(String[] args) throws Exception { /* Class对象获取的三种方式 1.通过Class.forclass("全类名")获取 2.通过类名.class()获取 3.通过对象.getClass()方法 */ // 1.通过Class.forclass("全类名")获取 Class cls1 = Class.forName("Five.TestReflection.Person"); System.out.println(cls1); // 2.通过类名.class()获取 Class cls2 = Person.class; System.out.println(cls2); // 3.通过对象.getClass()方法 Person p = new Person(); Class cls3 = p.getClass(); System.out.println(cls3); // 4.比较三个class引用所指向的是否为同一个Class对象 System.out.println("比较三个class引用所指向的是否为同一个Class对象"); System.out.println("cls1 == cls2:"+(cls1 == cls2)); System.out.println("cls1 == cls2:"+(cls1 == cls3)); } }/* output class Five.TestReflection.Person class Five.TestReflection.Person class Five.TestReflection.Person 比较三个class引用所指向的是否为同一个Class对象 cls1 == cls2:true cls1 == cls2:true */
注意
用途
在运行时操作对象
<!--举例-->
<!--运行过程中,以下出现的方法属于Class类对象中的methods对象中的内容-->
<!--可以想象成,Class为一个特殊类,其中Field为成员属性,这个成员属性中存在更加具体的成员属性,并且field这个成员属性能够通过get和set方法来获取和设置值-->
规则
注意
getFields和getDeclaredFields()获取时,getFields能够同时获取到超类和子类中的public变量,getDeclaredFields()只能获取到子类中的所有访问修饰类型的变量
<!--实现-->
// 超类 public class Father { // 成员变量 private String priFatherName; private int priFatherAge; public String pubFatherName; public int pubFatherAge; } // 子类 public class Son extends Father { // 成员变量 private String priSonName; private int priSonAge; public String pubSonName; public int pubSonAge; }
// 测试类 package Five.TestReflection; import java.lang.reflect.Field; public class TestField { public static void main(String[] args) throws Exception { /* getField和getDeclaredField */ // getField System.out.println("--测试getField"); Field[] field1 = Son.class.getFields(); for (Field f : field1) { System.out.println(f); } // getDeclaredField System.out.println("--测试getDeclaredField"); Field[] field2 = Son.class.getDeclaredFields(); for (Field f : field2) { System.out.println(f); }}} /* output --测试getField public java.lang.String Five.TestReflection.Son.pubSonName public int Five.TestReflection.Son.pubSonAge public java.lang.String Five.TestReflection.Father.pubFatherName public int Five.TestReflection.Father.pubFatherAge --测试getDeclaredField private java.lang.String Five.TestReflection.Son.priSonName private int Five.TestReflection.Son.priSonAge public java.lang.String Five.TestReflection.Son.pubSonName public int Five.TestReflection.Son.pubSonAge */
Field对象方法
Field
表示字段的值,指定对象上 Field
对象指定对象上的参数指定的新价值 setAccessible(): 忽略访问修饰符的安全检查,也称为暴力反射 (如果需要get或者set使用private修饰的变量,则需要使用该方法),用于调试,持久存储,相似机制。
<!--实现-->
// 超类 public class Father { // 成员变量 private String priFatherName; private int priFatherAge; public String pubFatherName; public int pubFatherAge; } // 子类 public class Son extends Father { // 成员变量 private String priSonName; private int priSonAge; public String pubSonName; public int pubSonAge; }
// 测试类 package Five.TestReflection; import java.lang.reflect.Field; public class TestField { public static void main(String[] args) throws Exception { /* get和set方法 */ Son son = new Son(); // get,public System.out.println("--测试get方法,使用getField,作用于public修饰对象"); Field field3 = Son.class.getField("pubSonName"); Object value3 = field3.get(son); System.out.println(value3); // get,private System.out.println("--测试get方法,使用getField,作用于private修饰对象"); // 由于getField只能作用于public修饰的成员,因此无法访问 // Field field4 = Son.class.getField("priSonName"); // field4.setAccessible(true); // Object value4 = field4.get(son); // System.out.println(value4); System.out.println("失败"); // get,private System.out.println("--测试get方法,使用getDeclaredField,作用于private修饰对象"); Field field5 = Son.class.getDeclaredField("priSonName"); // 获取前需要忽略访问的安全检查 field5.setAccessible(true); Object value5 = field5.get(son); System.out.println(value5); // set,public System.out.println("--测试set方法,使用getField,作用于public修饰对象"); Field field6 = Son.class.getField("pubSonName"); field6.set(son, "Toyz"); Object value6 = field6.get(son); System.out.println(value6); // set,private System.out.println("--测试set方法,使用getDeclaredField,作用于private修饰对象"); Field field7 = Son.class.getDeclaredField("priSonName"); // 获取前需要忽略访问的安全检查 field7.setAccessible(true); Object value7 = field7.get(son); System.out.println("修改前,priSonName:"+value7); field7.set(son, "QQ"); value7 = field7.get(son); System.out.println("修改前,priSonName:"+value7); } } /* output --测试get方法,使用getField,作用于public修饰对象 null --测试get方法,使用getField,作用于private修饰对象 失败 --测试get方法,使用getDeclaredField,作用于private修饰对象 null --测试set方法,使用getField,作用于public修饰对象 Toyz --测试set方法,使用getDeclaredField,作用于private修饰对象 修改前,priSonName:null 修改前,priSonName:QQ */
规则
getDeclaredConstructors():获取所有构造方法(包括private修饰,暴力反射,不含超类)
<!--实现-->
// 超类 public class Father { public Father(String priFatherName , int priFatherAge , String pubFatherName , int pubFatherAge) { this.priFatherName = priFatherName; this.priFatherAge = priFatherAge; this.pubFatherName = pubFatherName; this.pubFatherAge = pubFatherAge; } public Father() { } private Father(String priFatherName , int priFatherAge){ this.priFatherName = priFatherName; this.priFatherAge = priFatherAge; } } // 子类 public class Son extends Father { public Son(String priSonName , int priSonAge , String pubSonName , int pubSonAge) { this.priSonName = priSonName; this.priSonAge = priSonAge; this.pubSonName = pubSonName; this.pubSonAge = pubSonAge; } public Son(){} private Son(String priSonName , int priSonAge){ this.priSonName = priSonName; this.priSonAge = priSonAge; } }
// 测试类 public class TestConstructor { public static void main(String[] args) throws Exception { /* getConstructor和getDeclaredConstructor */ // getConstructor,无参构造器和有参构造器 System.out.println("--测试getConstructor"); Constructor constructor1 = Son.class.getConstructor(); System.out.println("无参构造器:"+constructor1); Constructor constructor2 = Son.class.getConstructor(String.class,int.class,String.class,int.class); System.out.println("有参构造器:"+constructor2); // getConstructors System.out.println("--测试getConstructors"); Constructor[] constructors3 = Son.class.getConstructors(); for (Constructor c : constructors3) { System.out.println(c); } // getDeclaredConstructor System.out.println("--测试getDeclaredConstructor"); Constructor constructor4 = Son.class.getDeclaredConstructor(String.class,int.class); System.out.println(constructor4); // getDeclaredConstructors System.out.println("--测试getDeclaredConstructors"); Constructor[] constructor5 = Son.class.getDeclaredConstructors(); for (Constructor c : constructor5){ System.out.println(c); } } } /* output --测试getConstructor 无参构造器:public Five.TestReflection.Son() 有参构造器:public Five.TestReflection.Son(java.lang.String,int,java.lang.String,int) --测试getConstructors public Five.TestReflection.Son() public Five.TestReflection.Son(java.lang.String,int,java.lang.String,int) --测试getDeclaredConstructor private Five.TestReflection.Son(java.lang.String,int) --测试getDeclaredConstructors private Five.TestReflection.Son(java.lang.String,int) public Five.TestReflection.Son() public Five.TestReflection.Son(java.lang.String,int,java.lang.String,int) */
Constructor对象方法
newInstance( Object ... initargs):利用这 Constructor
对象创建和初始化的构造函数的声明类的一个新实例构造函数,用指定的初始化参数。
<!--实现-->
// 测试类 public class TestConstructor { public static void main(String[] args) throws Exception { /* newInstance(Object... initargs) */ // newInstance(Object... initargs)无参构造器 System.out.println("--newInstance(Object... initargs) 无参构造器"); Constructor constructor6 = Son.class.getConstructor(); System.out.println(constructor6.newInstance()); // newInstance(Object... initargs)含参构造器 System.out.println("--newInstance(Object... initargs) 含参构造器"); Constructor constructor7 = Son.class.getDeclaredConstructor(String.class,int.class); constructor7.setAccessible(true); // 忽略访问的安全检查 System.out.println(constructor7.newInstance("Toyz",44)); } } /* output --newInstance(Object... initargs) 无参构造器 Son{priSonName='null', priSonAge=0, pubSonName='null', pubSonAge=0} --newInstance(Object... initargs) 含参构造器 Son{priSonName='Toyz', priSonAge=44, pubSonName='null', pubSonAge=0} */
规则
getDeclaredMethods():获取所有方法(包括private修饰,暴力反射,不含超类)
<!--实现-->
// 超类 public class Father { // 方法 public void eat(){ System.out.println("father eat..."); } public void eat(String food){ System.out.println("father eat..."+food); } public void edu(){ System.out.println("father edu..."); }; private void run(){ System.out.println("father run..."); } } // 子类 public class Son extends Father { // 方法 public void eat(){ System.out.println("son eat..."); } public void eat(String food){ System.out.println("son eat..."+food); } private void run(){ System.out.println("son run..."); } }
// 测试类 public class TestMethod { public static void main(String[] args) throws Exception { /* getMethod和getDeclaredMethod */ Son son = new Son(); // getMethod,空参方法 System.out.println("--测试getMethod,空参方法"); Method method1 = Son.class.getMethod("eat"); System.out.println(method1); // getMethods,所有方法 System.out.println("--测试getMethods"); Method[] method2 = Son.class.getMethods(); for (Method m : method2) { System.out.println(m); } // getDeclaredMethods,所有方法 System.out.println("--测试getDeclaredMethods"); Method[] method3 = Son.class.getDeclaredMethods(); for (Method m : method3) { System.out.println(m); }}} /* output --测试getMethod,空参方法 public void Five.TestReflection.Son.eat() --测试getMethods public java.lang.String Five.TestReflection.Son.toString() public void Five.TestReflection.Son.eat(java.lang.String) public void Five.TestReflection.Son.eat() public void Five.TestReflection.Father.edu() public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final void java.lang.Object.wait() throws java.lang.InterruptedException public boolean java.lang.Object.equals(java.lang.Object) public native int java.lang.Object.hashCode() public final native java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll() --测试getDeclaredMethods private void Five.TestReflection.Son.run() public java.lang.String Five.TestReflection.Son.toString() public void Five.TestReflection.Son.eat(java.lang.String) public void Five.TestReflection.Son.eat() */
Method对象方法
invoke( Object obj, Object ... args):第一个参数为隐式参数,静态方法时为null。调用底层的方法,这 方法
对象表示,对指定对象的指定参数。能够调用超类的方法
<!--实现-->
// 测试类 public class TestMethod { public static void main(String[] args) throws Exception { /* invoke */ // invoke,含参子类public方法 System.out.println("--测试invoke,含参子类public方法"); Method method4 = Son.class.getMethod("eat",String.class); method4.invoke(son, "Fish"); // invoke,含参父类public方法 System.out.println("--测试invoke,含参父类public方法"); Method method5 = Son.class.getMethod("edu"); method5.invoke(son); // invoke,无参子类private方法 System.out.println("--测试invoke,无参子类private方法"); Method method6 = Son.class.getDeclaredMethod("run"); method6.setAccessible(true); method6.invoke(son); } } /* output --测试invoke,含参子类public方法 son eat...Fish --测试invoke,含参父类public方法 father edu... --测试invoke,无参子类private方法 son run... */
步骤
实现
创建类(配置文件需要用到的示范类)
package Five.TestReflection; public class Father { public Father() { } // 方法 public void eat(){ System.out.println("father eat..."); } }
创建配置文件
className=Five.TestReflection.Father methodName=eat
读取并执行
package Five.TestReflection; import java.io.InputStream; import java.lang.reflect.Method; import java.util.Properties; public class TestReflection { public static void main(String[] args) throws Exception { // 1.加载配置文件 // 1.1创建pro对象 Properties properties = new Properties(); // 1.2加载配置文件,转换为集合 // 1.2.1获取配置文件路径 ClassLoader classLoader = TestReflection.class.getClassLoader(); InputStream is = classLoader.getResourceAsStream("pro.properties"); properties.load(is); // 2.获取配置文件中定义的数据 String className = properties.getProperty("className"); String methodName = properties.getProperty("methodName"); // 3.加载类进内存 Class cls1 = Class.forName(className); // 4.创建对象-反射 Object object = cls1.newInstance(); // 5.执行方法-反射 Method method1 = cls1.getMethod(methodName); method1.invoke(object); } } /* output father eat... */