-
访问权限控制
- 面向对象三大特征
- 基本特征:封装、继承、多态
- 封装:客观事物抽象,类将数据和方法,只让可信的类或对象操作,对不可信进行信息隐藏。
- 继承:主要允许和鼓励类的重用
- 多态:允许不同类的对象对同一消息做出响应;多态性语言具有灵活、抽象、行为共享、代码共享
- 封装
- 封装将过程和数据包围,对数据的访问只能通过已定义的接口;Java中通过控制成员访问权限进行封装。
- 包的概念和作用
- 包的作用:用于区别类名的命名空间
- 功能相似的接口和类组织在一个包,方便类的查找和使用
- 避免命名冲突:不同包可有相同名的类
- 提供限定访问权限,拥有包访问的类才能访问包中的类。
- 包作用总结:防止命名冲突、访问控制、提供全类名定位类、接口、枚举和注解等。同时将不同java程序分类保存,以便其他java程序调用。
- java JDK中的包
- java.lang:打包基础的类
- java.io:包含输入输出功能的函数
- java.util:包含一些重要的工具
- …
- 实际开发中:开发者将一组类等定义成自己的包。
- 包的作用:用于区别类名的命名空间
- package import 关键字
- package :表明将源程序中的类打成一个包
- Java编译器将包对应于文件系统的目录管理
- 实例:com.cj对应文件目录层次–com/cj
- import com.*:表示导入com包中所有类
- 注意:包与子包不存在继承关系,只要两个类不直接在同一文件中即认为位于不同的包,*只能包含本包中的类而不能包含子包中的类。
- 类目录的绝对路径classpath:CLASSPATH系统变量中。
- 编译器和JVM通过将package名字加到classpath后构成.class文件的路径。
- 例如:root\classes是class path,package名字是com.chinasofti,而编译器和JVM会在root\classes\com\chinasofti中找.class文件
- 一个class path可能包含几条路径,多路径应该用分隔符分开
- 默认情况下,编译器和JVM查找当前目录
- 包命名规则
- Java包约定:
- 名字内所有字母都应该小写
- 通常一个公司使用互联网域名的颠倒形式作为包名:例如 chinasofti.com,包名都应以com.chinasofti开头。
- Java包约定:
- javac -d参数
- 不使用-d参数,编译结果并不会生成包结构,即使package语句声明代码所在包,也会直接在当前文件夹直接生成.class文件。
- 使用-d参数:自动根据package语句生成目标目录结构(可能在代码动态编译动态加载时十分重要)
- 类访问控制符
- public :所有
- protected :同类 同包 不同包子类
- 默认 :同类 同包
- private :同类
- 类成员访问控制符
- 主要通过对类成员的权限访问隐藏数据而暴露操作接口
- 面向对象三大特征
-
继承
-
继承的意义
- 代码重用 继承是复用代码的方式
- 定义:子类继承父类特征和行为。
- java是单一继承
-
extends关键词
-
is - a 关系:
-
向上造型:继承关系中,继承者可以替换被继承者。
-
子类从父类继承的东西
-
子类拥有父类的属性和方法(private成员由于权限关系因此不能访问) 构造方法不能继承
-
注意:覆盖与继承的区别
对于覆盖: 子类不能覆盖父类属性、静态方法、静态属性
解释:静态方法和静态属性不是放在实例中
-
-
子类拥有自己的属性和方法
-
Java根节点为Object、所有Java中的类直接或间接继承Object
-
Java根节点为Object、所有Java中的类直接或间接继承Object
-
-
-
构造方法与继承
- 子类无法继承构造方法
- 构建子类对象时,会优先隐形自动调用父类的无参构造方法。 这个请参考双亲委托模型
- 总结:父类最好给出一个无参构造方法。
-
super关键词
- 作用:
- 当我们希望调用父类数据和方法。
- 主要解决父类变量的初始化问题:子类中某个继承自父类的方法可能会使用父类的某些变量,而这些变量并没有进行初始化,可能产生一些难以预料的后果。
- super:在子类构造方法中显式调用父类的构造方法,调用必须位于第一行,保证父类被初始化。
- 注意:对于没有无参的父类构造方法,子类必须显式的调用父类的构造方法。并且必须是子类构造器中的第一行(表示第一件事);或者当我们需要初始化某些父类变量以便子类使用时。
- 作用:
-
方法覆盖
-
方法覆盖的作用
- 子类希望修改父类的方法的方法体 两种方式
- 1.子类创建一个不同名字的新方法,实现新逻辑。这样破坏封装性 ----不管
- 2.方法覆盖:方法声明形式与父类方法相同,但具体方法体不同。
- 子类希望修改父类的方法的方法体 两种方式
-
方法覆盖的规则
- 方法名、参数列表必须完全一致;
- 返回值如果为基本数据类型,返回值应该保持一致;如果返回值为类,则返回值必须为父类方法返回值或其的子类(协变返回类型)。
- 子类抛出异常不能超过父类对应方法抛出的异常,即为应为父类异常的子类
- 子类方法访问权限不能低于父类方法的访问级别。即父类为默认,子类必须为public或相同。
-
super关键词在方法覆盖中的使用
-
使用super显式调用父类方法:
当我们需要明确使用父类声明的方法版本时。
-
可以使用super来显式调用父类成员:
子类可以声明和父类同名的成员变量,此时在子类中通过变量名访问,使用的是子类自己定义的成员。
-
注意:与this不同,super不是一个真正意义上的引用。
-
-
-
-
多态性
-
多态性定义
- java多态性:允许不同类的对象对同一信息做出响应。同一消息根据发送对象的不同采用不同的行为方式。(注意这里是父类对象(子类对象).方法)
- 主要作用:适用消除类型之间的耦合关系。???
- Java多态实现:程序中定义的引用变量所指向的具体类型和通过引用变量发出的方法调用在编译时并不确定,而是在程序运行时才确定。
- 解释:即引用变量具体会指向哪个类的实例对象,以及引用变量发出的方法调用是哪个类中的方法,必须在程序运行期间才能决定。
- 好处:程序运行时才确定具体的类,我们可以不修改源程序代码,从而让引用变量绑定到各种不同的类实例上,从而导致该引用调用的具体方法随之改变。 总结:不修改程序代码就可以改变程序运行时绑定的具体代码,让程序可以选择多个运行状态。
-
对象向上造型
-
向上造型:父类的引用(栈)指向子类的对象(堆)
Parent p=new Child(); Child c=new Parent();//错误
-
子类转父类,可直接转;父类转子类,需要强制转
-
-
编译期类型与运行期类型
-
编译期类型:进行对象造型时,声明引用的父类类型
-
运行期类型:实际用于构建对象的子类类型
-
!:引用变量在编译阶段调用编译期类型所具有的方法,但运行时则执行它运行时类型具有的方法
-
向下造型:即显式将父类引用指向的对象转换为子类类型
-
向下造型要求:进行向下造型的对象的运行期类型必须是子类或以子类为根的继承树中的其他类型
Ostrich extends Bird //正确实例: Bird bird=new Ostrich(); Ostrich ostrich=(Ostrich)bird; //错误实例:这里没有符合向下造型要求 Bird bird=new Bird(); Ostrich ostrich=(Ostrich)bird;
-
-
-
多态环境下对属性和方法的调用特定
- Java代码的变量和方法进行绑定(即通过对象调用成员变量或方法时究竟调用哪个版本)的时候划分为两种:
- 静态绑定:发生在编译时期
- 类的成员变量(属性)都是静态绑定。所以类中声明的成员变量不能被子类中同名属性覆盖,通过该类的引用调用成员变量,调用该类自身的属性。
- 动态绑定:发生在运行时
- 对于Java中方法,除final、static、pricvate、和构造方法是静态绑定,其他方法全部为动态绑定。
- 换言之就方法调用将动态使用运行期类型的方法
- 由于这里对重载方法和重写方法的区别有疑惑所以
- 重载方法:一个类中定义多个同名的方法
- 具体调用哪个版本通过静态绑定在编译器决定
- 重写方法:子类重写父类的方法
- 通过动态绑定在运行期决定
- 重载方法:一个类中定义多个同名的方法
- 静态绑定:发生在编译时期
- Java代码的变量和方法进行绑定(即通过对象调用成员变量或方法时究竟调用哪个版本)的时候划分为两种:
-
多态参数的使用
- 将方法的形参参数声明为父类类型,由于将子类对象赋给父类引用是合法的,所以实参可以是以形参类型为根的继承树的任意类型
-
instanceof运算符
-
应用场景:需要明确参数的运行期类型是什么时
-
instanceof:判断对象是否属于某个类的实例
具体语法:对象 instanceof 类 //boolean表达式
-
-
多态总结
- 多态:执行期间判断引用对象的实际类型,根据实际类型调用相应的方法
- 多态存在的3个必要条件
- 继承
- 重写覆盖
- 对象向上造型–子类对象赋给父类引用
- 多态好处:
- 可替换性
- 可扩充性
- 增加新的子类不影响已存在类的运行。
- 接口性
- 灵活性
- 简化性
-
-
抽象
- 抽象的作用
- 就是只声明行为接口,而不具体实现
- 抽象类
- abstract 修饰符。抽象类是抽象方法的容器,可以有抽象方法或者非抽象方法。
- 抽象类不可以实例化
- 抽象类派生子类必须实现抽象类中所有抽象方法
- 抽象方法
- 抽象的作用
-
final修饰符
- 常量
- final修饰变量:表明该变量为常量,且该常量在声明时必须初始化,声明后不能对其二次赋值。否则会报错
- final方法
- final修饰成员方法:表明该方法不能被子类覆盖(即重写);注意:这里与抽象方法必须由子类实现相互矛盾,所以final和abstract不能同时修饰一个方法。
- final类
- final修饰类:表明该类无法被继承
- 常量
-
static
- static成员特征
- 有些属性是群体中每个个体共享取值的
- 针对每个类所有对象的共性属性,Java采用static成员统一调用
- static在变量或方法前,表明它们属于类,称类方法或类变量。否则为实例方法或实例变量
- static成员存放位置:不存放在对象对应的堆空间,而是存放到方法区中,每个对象的相应static共享同一段内存。
- static属性
- 静态成员变量:static修饰成员变量
- 所有对象共享静态成员变量
- 静态成员变量作用域在类内部
- 访问静态成员变量:
- 没有实例化对象,可以通过类名访问静态成员变量
- 也可以通过对象访问静态成员变量,无论使用哪个对象访问的都是同一个变量
- 建议:不管是否有对象均由类名调用,这样更符合逻辑
- static final常量
- 一个变量同时被static和final修饰,与static修饰相比区别在于在声明时必须初始化,且不能二次赋值
- 通常用于保存整个应用程序共享的变量值
- static方法
- 静态成员方法:static修饰成员方法
- 注意:静态成员方法只能对方法中的局部变量或类的静态成员变量进行操作
- 注意2:静态成员方法没有this引用
- 静态成员方法访问:
- 同静态成员变量访问方式
- static方法和实例方法之间互相调用的情况
- 实例方法可以直接调用static方法及static成员变量
- static方法无法直接调用实例方法及非static成员变量,如果要调用,只能在方法体中构建一个对象,利用该对象调用
- static方法可以调用别的static方法
- static import
- jdk1.5中引入,用于略掉所在类或接口名的方式使用静态成员
- static import java.lang.Math.*:表示导入Math类中所有的静态成员(一切被static修饰的东西),包括变量,常量,方法和内类
- 注意:这个导入仍然受java访问控制机制的限制
- 注意1:如果同类包括名称相同的静态成员
- 如果两个语句都是精确导入的形式,或者都是按需导入的形式,那么会造成编译错误。
- 如果一个采用精确导入,一个采用统配符*按需导入,那么精确导入的有效
- this为什么不能在static方法中使用
- 非静态方法可以使用this,因为非静态方法参数传递时,有一个隐式参数this
- 静态方法属于类而不属于某个对象。在加载类时已经被JVM初始化,所以不存在this隐式参数。如果要调用非静态域,我们可以通过显式参数传递idea方式实现。
- static成员特征
-
接口 interface
-
接口作用与定义
-
面向接口编程:指在oop系统中所有类或者模块之间的交互由接口完成
-
定义:
访问权限 interface 接口名{ 公开静态常量列表; 公开抽象方法列表; }
-
接口:比抽象类更为抽象的概念,区别
- 属性:抽象类 不同限制 interface public静态常量
- 构造方法:可有可无 没有
- 普通方法:可以有具体方法 必须为public抽象方法
- 子类:单一继承 多重实现
-
-
接口中的常量、方法
- 成员变量只存在公开静态常量 默认public static final
- 成员方法只存在公开抽象方法 默认public abstract
-
类实现接口
- implements
- 子类可多重实现
- 定义多个类都要实现的操作
-
接口的继承
-
java接口继承接口的形式
Interface3 extends Interface0,Interface1,...{ }
-
java接口继承是多重继承,而java类继承是单一继承
-
接口可多继承原因:
- DDD(Dreadful Diamond onDerivation):中文译名钻石问题或讨嫌的菱形派生 类无法多重继承的原因: 如果A同时继承B和C,而B和C同时有一个D方法,A会无法确定该继承哪一个。
- 接口全是抽象方法,不存在实现冲突
-
-
JDK8接口的默认方法
-
java8之前,接口不能升级。因为在接口中添加一个方法,会导致老版本的所有实现类的中断(即所有的类都要重写新加的方法,不然就会错误)
-
默认方法是库/框架设计者的后悔药。
- 对于这句话的解释:
- 对于不想要添加功能的接口实现类,不去调用,不去实现。对于不想添加功能又有同名方法的接口实现类,根据默认方法的规则,默认方法也是不可见的。
- 对于要添加功能的接口实现类,我们去重写这个方法,那么做到添加了新的功能。对于要添加功能又有同名方法的接口实现类,我们更改默认方法的名字就ok。
- 默认方法的规则:类型层次中任何符合override规则的方法,优先于默认方法。
- 对于新代码:因为遗留代码中可能正好有同样的方法存在。(也就是说实现该接口的类中可能恰好有与我们新增的默认方法同名的方法,此时应该是符合override规则的方法优先)
- 对于这句话的解释:
-
但是由于java8,lambda表达式作为核心出现,为了配合lambda表达式Collection库需要添加新的方法,如forEach、stream等。于是引入默认方法(defender methods,Virtual extension methos)
-
默认方法的声明
default 返回值 默认方法名(){ 方法体 }
-
默认方法带来的多继承问题:也就是上述的钻石问题
public interface A{ default void foo(){ 打印Calling A.foo(); } } public interface B{ default void foo(){ 打印Calling B.foo(); } } //这里两个接口的foo默认方法冲突 不能正常编译 class Clazz implements A,B{ }
-
必须通过手动重写冲突的方法解决
class Clazz implements A,B{ public void foo() { //显式调用某版本的默认方法 A.super.foo(); } }
-
解决多继承冲突的原则
- 情况一,接口IA有子接口IB1、IB2,而类C implements IB1、IB2;当IB1、IB2都重写了IA接口方法。
-
-
-
-
枚举
-
枚举概念
-
枚举的声明
-
基本声明格式
访问权限 enum 枚举名{ 枚举值列表 }
-
-
枚举的使用
-
在switch语句中使用
public enum Color{ RED("红色",1),GREEN("绿色",2); private String name;//成员变量 private int index; //构造方法,在列举枚举值时调用 private Color(String name,int index){ this.name=name; this.index=index; } //普通方法 public String getName(){ return name; } }
-
所有枚举都继承自java.lang.Enum类。所以不能继承其他类,单可以实现接口。
-
无public构造方法
-
枚举值都是public static final
-
Enum 默认实现java.lang.Comparable接口
-
Enum重载了toString方法
-
自己去看Enum api
-
-
-
关联与依赖
-
类的关联关系
- 通俗来讲就是 一个类含有另一个类的对象属性
-
一对一、一对多关系举例
-
关联关系的意义
-
体现has a 关系
-
细分为聚合和组合
-
聚合:表示整体对象拥有部分对象。
public class Human{ House myHome; } class House{ }
-
组合:强调整体与部分的生命周期是一致的。
public class Human{ Heart myHeart=new Heart(); } class Heart{ }
-
-
-
依赖关系的代码表示
-
体现use a 关系
-
例如这里,空气与人类的关系;空气不过是人类的一个工具,而人类并不持有对它的引用。
public class Human{ DrivingLicense license; CertificateOfHonor[] certificates; public void breath(Air freshAir){ } }
-
-
-
内部类
-
内部类作用
- 内部类:即在一个类的内部定义另一个类,此时内部类就成为外部类的成员。访问权限遵循类成员的访问权限机制
- 某些内部类可以方便的访问外部类的其他成员
- 内部类实现一些特殊的需要
- 完善多重继承?
- 原因:每个内部类都能独立地继承一个接口的实现,所以无论外部类是否已经继承某个接口的实现,对内部类没有影响。
- 形成闭包?
- 面向对象的闭包,因为内部类不仅包含创建内部类的作用域的信息,还自动拥有一个指向其外部类对象的引用,内部类作用域内,内部类有权操作所有的成员,包括private成员。
- 完善多重继承?
-
内部类声明与使用
public class OuterClass{ private String name; private int age; //成员内部类 public class InnerClass{ public InnerClass(){ name="Jerry"; age=23;//这里可以直接访问外部类的成员变量 } public void display(){ System.out.println("name:"+name+" ;age:"+age); } } public static void main(Stirng[] args){ //注意构建内部类的形式 //1.首先构建外部类对象 //2.以外部类.内部类的形式进行声明 //3.以外部类对象.new 内部类构造方法()的方式构建对象 OuterClass outerClass=new OuterClass(); OuterClass.InnerClass innerClass=outerClass.new InnerClass(); } }
-
内部类:编译时概念,一旦编译成功,就与外部类属于两个完全不同的类(当然还是有联系)
-
含内部类的类编译后的class文件:OuterClass.class和OuterClass$InnerClass.class
-
内部类主要分:
- 成员内部类、局部内部类、匿名内部类、静态内部类
-
成员内部类介绍:
- 成员内部类对外部类访问规则:成员内部类可以无限制访问外部类所有成员属性和方法。但是外部类访问内部类成员属性和方法需要通过内部类实例访问。
- 注意:
- 成员内部类不能存在任何static的变量和方法
- 成员内部类依附外部类,只有先创建外部类才能创建内部类。
- 成员内部类的创建以及对象的创建见上面的例子
-
局部内部类介绍:
-
嵌套在方法和作用域,只在方法和作用域中被使用,出了方法和作用域就会失效。
-
主要是我们想创建一个类辅助我们的解决方案,又不希望该类公共可用时。
public class OuterClass{ private String name; private int age; public void display(){ //定义局部内部类 class InnerClass{ public InnerClass(){ name="Jerry"; age=23; } public void display(){ //打印年龄和姓名 } } } public void display(int arg){ //定义局部内部类 class InnerClass{ public InnerClass(){ name="Jerry"; age=arg;//这里的方法临时变量并非是final常量,读取会报错。 //但是如果我们将方法参数改为final int arg的话就可以读取 } public void display(){ //打印年龄和姓名 } } //创建局部内部类实例,调用局部内部类方法 InnerClass ic=new InnerClas(); ic.display(); } public static void main(String[] args){ OuterClass outerClass=new OuterClass(); outerClass.display(); } }
-
局部内部类对外部类变量访问规则:
- 局部内部类也可直接操作外部类成员变量,但对于方法的临时变量(包括方法的参数,要求是final常量才能操作)
-
-
-
内部类操作外部类成员和方法临时变量的规则
-
静态内部类 或static内部类 或嵌套内部类
-
静态内部类:static修饰的内部类
-
静态内部类与非静态内部类区别:
- 非静态内部类在编译成功后会隐含一个引用,该引用指向外部类。但是静态内部类没有,意味着:
- 它的创建不需要依赖于内部类
- 不能访问外部类的非static成员变量和方法
- 与成员内部类不同,static能够声明static的成员
public class OuterClass2{ private String name; private static String name="Jerry"; //静态内部类 static class InnerClass1{ //可以定义static成员 public static String staticName="Jerry_static"; public void display(){ //打印 staticName; } } // public void display(){ System.out.println(InnerClass.staticName); //static静态内部类构建对象不需要依赖外部类的对象 new OuterClass2.InnerClass1().display(); } public static void main(String[] args){ OuterClass2 outer=new OuterClass2() ; outer.display(); } }
- 非静态内部类在编译成功后会隐含一个引用,该引用指向外部类。但是静态内部类没有,意味着:
-
-
内部类的this及类名.this的使用
-
内部类本质上是一个独立的类,所以在内部类中直接使用this,其指代的是内部类自身的引用,如果想要引用外部类的对象,应该使用外部类类名.this的方式。
public class OuterClass3{ int i=10; public class InnerClass{ int i=100; public void display(){ //打印this.i 当然为100 //打印OuterClass3.this.i 为10 } } }
-
-
匿名内部类
-
匿名内部类:不存在名字的内部类
-
匿名内部类必须继承一个父类或实现一个接口
-
匿名内部类的声明使用方法:
访问权限 修饰符 父类名/接口名 引用名=new 父类名/接口名([父类构造方法参数列表]){ 匿名内部类成员; } 实例 public class AnonymousInnerClass{ private String name="Jerry"; private int age=24; IFoo foo=new IFoo(){ public void display(){ //打印name和age } }; public static void main(String[] args){ AnoymousInnerClass aiClass=new AnoymousInnerClass() ; aiClass.foo.display(); } } interface IFoo(){ public void display(); }
-
匿名内部类对类成员、方法临时变量的访问规则和具备名字的内部类保持一致。
-
-
JDK8lambda表达式
-
主要替换了匿名内部类的写法
-
lambda语法结构:
-
(参数列表)->{expression/方法体}
实例 ()->5:表示不需要参数,返回值为5 x->2*x:表示接受一个参数,返回2*x的值 (x,y)->x-y:表示接受两个参数,并返回它们的差值 (int x,int y)->x+y: (String s)->syso(s)
-
-
注意:JDK8提供的lambda表达式并不会被编译成带$的匿名内部类
-
lambda是方法的实现
-
lambda是延迟执行的
- 编译后只是定义了一个方法调用点,具体调用要到运行时才决定
public class AnonymousInnerClass{ private String name="Jerry"; private int age=24; IFoo foo=()->syso("age"+age);//这里会自动检索匹配对应的返回类型 public static void main(String[] args){ AnoymousInnerClass aiClass=new AnoymousInnerClass() ; aiClass.foo.display(); } } interface IFoo(){ public void display(); }
-
-
JDK8函数式接口
- lambda表达式对返回的实例类型有比较严格的要求
- 必须为接口且接口只有一个需要实现的抽象方法。
- 函数式接口:仅仅包含一个抽象方法的接口。因为默认方法不算抽象方法,所以也可以给函数式接口添加默认方法。
- @FunctionalInterface:用于确保接口为函数式接口。如果编译器发现标注的接口有多余一个抽象方法的时候会报错。
- lambda表达式对返回的实例类型有比较严格的要求
-
Lambda作用域
- lambda表达式访问外层作用域和老版本的匿名内部类方式很相似。
- 可以直接访问标记final的外层局部变量,或实例成员变量及静态变量。
-
Lambda与接口的默认方法
- Lambda表达式无法访问到默认方法
-
JDK8的::关键字
-
::主要用于静态方法、成员方法或构造方法的绑定
public class FunctionBindOp{ public static void main(String[] args){ IntegerFactory factory=Integer::valueOf;将函数式接口需要实现的方法与Integer类的valueOf静态方法绑定(注意返回值和参数列表) } Integer integer=factory.createInteger("123"); syso(integer.intValue()); }
-
绑定实例成员方法:
public class FunctionBindOp2{ public void foo(){ syso("解绑的成员方法"); } public static void main(String[] args){ FunctionBindOp2 fBindOp2=new FunctionBindOp2() ; IBFoo ifoo=fBindOp2::foo;//绑定实例方法 ifoo.ifoo(); } } interface IBFoo{ public void ifoo(); }
-
绑定构造方法:
public class Person{ String firstName; String lastName; Person(String firstName,String lastName){ this.firstName=firstName; this.lastName=lastName; } public static void mian(String[] args){ PersonFactory personFactory=Person::new;//通过new绑定构造方法 Person person=personFactory.create("Jerry0","Zhou"); syso(); } } interface PersonFactory{ Person create(String firstName,String lastName); }
-
-
问题:内部类实现一些特殊的需要
- 完善多重继承?
- 形成闭包?这些主要是指什么,能举出例子吗?
问题:子类是否可以重载从父类重写的方法。
Parent p=new Child();
p.say();
//这个say(String s)就是子类重载从父类重写的方法,这里通过p是无法调用的
//p.say("hello");
//问题:子类是否可以重载从父类重写的方法。
//语法上没有问题 ,但是只暴露了父类的接口,在向上转型的情况下只能调用重写父类的那个方法。如果要调用子类中重写父类的那个方法,应该具体的new一个子类出来,然后调用重载方法。这样就打破了六大原则。
Child c=new Child();
c.say("hello");