个人笔记,没有参考价值😈,为节约您的学习时间,请绕道查找其他资料
public class OverloadTestAppMain {
public static void main(String[] args) {
LittleSuperMarket superMarket = new LittleSuperMarket("大卖场",
"世纪大道1号", 500, 600, 100);
MerchandiseV2 m = superMarket.getMerchandiseOf(100);
MerchandiseTest merchandiseTest = new MerchandiseTest();
System.out.println("-----------1-------------");
// TODO 重载调用哪个方法,和参数的引用类型相关,和引用实际指向的类型无关
merchandiseTest.testMerchandiseOverload(m);
merchandiseTest.testMerchandiseOverload((Phone) m);
merchandiseTest.testMerchandiseOverload((ShellColorChangePhone) m);
// TODO 甚至是个null也可以,但是要用强制类型转换,告诉Java这个类型是什么,否则找不到一个唯一的方法去调用
// TODO 重载的参数类型,相同位置,不一定要有继承或者兼容的关系,完全free style
merchandiseTest.testMerchandiseOverload("");
System.out.println("-----------2-------------");
System.out.println();
// >> TODO 引用本身是null没关系,确定调用哪个方法只需要引用的类型。这叫做静态多态。即在编译期就知道该调用哪个方法
m = null;
merchandiseTest.testMerchandiseOverload(m);
merchandiseTest.testMerchandiseOverload((Phone) m);
merchandiseTest.testMerchandiseOverload((ShellColorChangePhone) m);
System.out.println("-----------3-------------");
// >> TODO 如果引用类型没有完全匹配的,则会根据继承关系,沿着参数当前类型,向下撸
merchandiseTest.testMerchandiseOverloadNotExactlyMatchType((ShellColorChangePhone) null);
// >> TODO 重载总结:静态多态,调用的方法和参数实际指向的对象无关,只和引用本身的类型相关。
// >> TODO 因为调用时参数类型是确定的,所以,在编译期间就可以明确的知道哪个方法会被调用。如果有多种可能,则会有编译错误
// >> TODO 如果没有类型完全匹配的候选,则根据类型的继承关系向下撸着找。找到最贴近参数类型的那个方法
// >> TODO 无论是静态方法,还是成员方法,重载寻找方法的顺序是一样的,在这里就不赘述了
// TODO (再提一句多继承,Java没有多继承,是前辈给我们的馈赠。保护了发际线。心疼隔壁CPP的程序员)
}
}
instanceof 操作符,可以判断一个引用指向的对象是否是某一个类型或者其子类
是则返回true,否则返回false
如果引用是null 则肯定返回false
protected 访问控制符对同一个包可见,还可以对子类可见,是为继承专门打造的访问控制符
protected = default + 继承者可见
子类覆盖父类的方法,不可以用可见性更低的修饰符,但是可以用更高的修饰符
解释: 这是和多态的特性有关系的,因为父类的引用可以指向子类的实例,万一我要调用这个子类的这个覆盖了父类的方法,但是如果子类中这个方法的访问权限更低的话,就可能不能用父类的引用类型来调用这个方法了,这和多态的特性是冲突的。
final 修饰符最见不得变化
- final 修饰类:不可被继承
- final 修饰方法:不可被子类覆盖
- final 修饰变量:不可被赋值
- final 修饰成员变量就意味着这个变量不能被修改,并且这个值必须要在构造方法里给它赋值,或者声明变量的时候赋值(这两种赋值操作只能且必须二选一,但如果深入理解的话,其实这两种赋值是一样,都是放在<init>方法里)
- 用 final 修饰静态变量也是必须要初始化(赋值),声明静态变量的时候或者在static代码块中(这两种方法只能且必须二选一)
-
用 final 修饰引用:我这个引用上放的地址是不能改的,只能指向初始化时指向的实例,但是我实例的内容是可以改的
用 final 修饰引用
Class实例是描述类的类
怎么描述的呢?
Class clazz = m100.getClass();
Field countField = clazz.getField("count");
System.out.println(countField.getName()); // 得到的结果是 count
System.out.println(countField.getType()); // 得到的结果是 int
- 例如通过 Class 类的 getField() 方法可以取得类里定义的成员变量,这个方法返回的结果可以调用很多方法,其中getName() 方法可以得到这个成员变量的名字, getType() 方法可以得到这个成员变量的数据类型,等等还有很多方法
Field 类的实例的方法
// class.getMethod("meted name", param type.class, [param type.class ...])
Method buyMethod = clazz.getMethod("buy", int.class, String.class);
Method equalsMethod = clazz.getMethod("equals", Object.class);
-
通过 Class 类的getMethod() 方法可以取得类里定义的方法,然后可以通过这个方法返回的结果来调用一些方法来描述当前得到的方法
Method 类的实例的方法
变长参数(动态参数)
public class testDynacArgs{
public static void dyncArgs(int a, String... args){
}
public static void main(String[] args){
dyncArgs(1); // --> dyncArgs(1, new String[0])
dyncArgs(1, "aaa"); // --> dyncArgs(1, new String[]{"aaa"})
dyncArgs(1, "aaa", "bbb"); // --> dyncArgs(1, new String[]{"aaa", "bbb"})
}
}
Class 类的 getField() 方法可以获得类中成员变量的定义
getMethod() 方法可以获得类中方法的定义
Class clazz = MerchandiseV2.class;
Field countField = clazz.getField("count");
System.out.println(countField.get(m100));
countField.get(m100); 这个语句相当于 m100.count;
countField.get(m100) 这个get()方法传一个对象给他,就会返回这个对象对应的这个field的值,在这个例子中这个对象对应的field就是count,他的是100(给出的示例代码中没有展现值为100哦~,不要纠结)
Method buyMethod = clazz.getMethod("buy", int.class);
System.out.println(buyMethod.invoke(m100, 10));
// 如果是通过反射调用静态方法的话,那么 invoke() 方法里第一个参数(对象)可以直接填null,有参数还是要填参数
// 例如 buy 是一个静态方法
// System.out.println(buyMethod.invoke(null, 10));
clazz.getMethod("buy", int.class) 这个方法是传一个方法名和这个方法的参数类型(相当于是方法的签名)给他,他会返回这个方法的一个实例
buyMethod.invoke(m100, 10) 这个方法的第一个参数要传是在那个实例上调用这个方法(这个例子中就是要在名m100这个实例上调用),第二个参数是要传一个实参。
注意⚠️ 有个反射特有的功能,Field 类的 getDeclaredField() 方法就是返回我在类中声明的成员变量,不要管我声明的时候是能不能访问,然后通过这个方法返回的对象调用 setAccessible("true") 方法,就可以把声明为 private 访问修饰符的方法强制转为可以访问的方法,实例代码如下:
Class clazz = MerchandiseV2.class;
Field countField = clazz.getDeclaredField("count");
countField.setAccessible(true);
System.out.println(countField.get(m100));
countField.set(m100,999);
System.out.println(countField.get(m100));
思考:反射是什么?
面向对象三要素:封装、继承、多态
- 封装解决了什么问题?
封装解决了数据层面的问题--》将成员变量封装在一起作为一个统一的类型定义 - 继承解决了什么问题?(和继承如影随形的又一个叫做组合的东西,而相对组合来说,继承是一种”融合“的关系)
就是我已经有一个类了,但是我需要一个其他的类,他们两又很像,这时候就可以用继承来节省代码量 - 多态解决了什么问题?
我继承了你,但是我有一种形态和父类中的行为不同,这就是多态最重要的一种--覆盖;当然多态还有重载...
枚举 enum
// 从键盘输入去匹配枚举类型
Scanner in = new Scanner(System.in);
System.out.println("请输入枚举的名字:");
String categoryName = in.next();
Category enumInput = Category.valueOf(categoryName.trim().toUpperCase());
- 枚举类的构造方法是 private 修饰的,通常省略修饰符(默认就是private)
枚举类的一些方法
- ordinal() 返回这个实例在枚举类中定义时的顺序
- name() 返回这个实例在枚举类中定义时的名字
网友评论