继承与多态
文章目录
继承的概念
实现代码的重用,提供程序的可维护性
子类的设计
格式:
[修饰符] class 子类名 extends 父类名
- 修饰符 ,可选 用于指定类的访问权限,可选值 public、abstract、final
- extends 必选 用于指定要定义的子类是继承于哪个父类
继承的原则
- 子类可以继承父类中被声明public、protected的成员变量和成员方法
- 子类能够继承在同一个包中由默认修饰符修饰的成员变量和成员方法
- 若子类声明一个与父类的成员变量同名的成员变量,此时子类的成员变量会隐藏父类的成员变量
- 若子类声明一个与父类的成员方法同名(而且 参数个数、类型和顺序也相同)的成员方法,此时子类 不能继承父类的成员方法,此时子类的成员方法覆盖父类的成员方法
子类的继承
子类可以继承父类的非私有成员变量和成员方法(不是以 private关键字修饰的)但是若子类和父类有同名的成员变量和成员方法时,父类的成员变量被隐藏,父类的成员方法被覆盖, 在子类中访问父类中被子类 隐藏的成员变量或方法,需要用到super关键字
super关键字作用:
- 调用父类的构造方法。 子类可以调用父类的抽象方法,但是必须在子类的构造方法中调用 super ([参数列表]);
- 操作被隐藏 的成员变量和被覆盖的成员方法
super.成员变量名
super.成员方法名([参数列表])
多态
使用方法的重载(Overloading)和覆盖(Overriding)来实现多态
方法的重载
在一个类中,出现多个方法名相同,但参数个数、参数类型、不同的方法,Java在执行有重载关系的方法时,将根据调用参数的个数和类型区分具体执行哪个方法;
重载的方法之间 并不一定必须有联系,但是为了提高程序的可读性,只重载功能相似的方法;
方法的返回值类型不能作为区分方法的重载的标志
方法重载之间 必须保证参数不同,但需要注意的是,重载方法在被调用时,可能出现调用歧义,
定义一个 名为Calculate的类,在该类中定义两个名为getArea()的方法(参数个数不同)和两个名为draw()的方法(参数类型不同)
public class Calculate{
final float PI = 3.1415926F;
public float getArea(float r){
float area = PI*r*r;
return area;
}
public float getArea(float l,float w){
float area = l*w;
return area;
}
public void draw(int num){
System.out.println("画"+num+"个任意形状的图形")
}
public void draw(String shape){
System.out.println("画一个"+shape);
}
public static void main(String [] args){
Calculate calculate = new Calcalate();
float l =20;
float w = 30;
float areaRectangle = calculate.getArea(l,w);
System.out.println("求长为"+l+"宽为"+w+"的矩形的面积是:"+areaRectangle);
float r = 7;
float areaCirc = calculate.getArea(r);
System.out.println("求半径为:"+r+"的圆形面积是:"+areaCirc);
int num = 7;
calculate.draw(num);
calculate.draw("三角形");
}
}
方法的覆盖
子类不能覆盖父类中声明 为final或者static的方法
子类必须覆盖父类中声明为abstract的方法,或者子类也将该方法声明为abstract
子类覆盖父类中的同名方法,子类中方法的声明也必须和父类中被覆盖的方法的声明一样
向上转型
创建抽象的动物类,在该类中定义一个 move()移动方法,并创建两个子类:鹦鹉和乌龟,在Zoo类中定义free()放生办法,该方法接受动物类作为方法参数,并调用参数的move()方法使动物获得自由
abstract class Animal{
public abstract void move(){
}
}
class Parrot extends Animal{
publiv void move(){
System.out.println("Parrot is fly");
}
}
class Tortoise extends Animal{
public void move(){
System.out.println(Tortoise is run");
}
}
public class Zoo{
public void free(Animal animal){
animal.move();
}
public static void main(String[] args){
Zoo zoo = new Zoo();
Parrot parrot = new Parrot();
Tortoise tortoise = new Tortoise();
zoo.free(parrot);
zoo.free(tortoise);
}
}
抽象类
只声明方法而不去具体实现它的类
抽象类不能被实例化,
abstract class 类名{
类体
abstract <方法返回值类型> 方法名(参数列表)
}
在抽象类中创建没有实现,必须要子类重写的方法成为抽象方法,只有方法的声明,没有方法的实现,用关键字abstract修饰
抽象方法不可使用private、static修饰;
抽象类
- 抽象类和抽象方法必须用abstract修饰
- 抽象类不可被实例化,无法使用new方法调用抽象类的构造器创建抽象类的实例;
- 抽象类中可以包含 属性、抽象方法、普通方法、构造器、初始化块、内部类、枚举类,构造器 主要适用于被子类调用,自己 不可用于创建实例
- 含有抽象方法的类 只能被定义为抽象类 (直接定义一个抽象方法、继承一个抽象父类,但没有实现父类的抽象方法、实现一个接口但没有完全实现接口包含的抽象方法)
final修饰符 讲解
修饰成员变量:
定义final变量时,要么指定初值,要么在初始化块、构造器中初始化成员变量
修饰局部变量
要么在指定初始值,要么 在后面的代码中赋值,只能赋一次值
修饰方法
使用final修饰方法 是不可以重写的,
static修饰符讲解
内部类
在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类
为什么在Java中需要内部类?总结一下主要有以下四点:
1.每个内部类都能独立的继承一个接口的实现,所以无论外部类是否已经继承了某个(接口的)实现,对于内部类都没有影响。内部类使得多继承的解决方案变得完整,
2.方便将存在一定逻辑关系的类组织在一起,又可以对外界隐藏。
3.方便编写事件驱动程序
4.方便编写线程代码
个人觉得第一点是最重要的原因之一,内部类的存在使得Java的多继承机制变得更加完善
成员内部类
概念定义:
成员内部类是最普通的内部类,它的定义为位于另一个类的内部,形如下面的形式
class Circle { //外部类
double radius = 0;
classDraw { //内部类
public void drawSahpe() {
System.out.println("drawshape");
}
}
public Circle(double radius) {
this.radius = radius;
}
}
内部类访问外部类
Circle称为外部类。成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。
class Circle {
private double radius = 0;
public static int count =1;
public Circle(double radius) {
this.radius = radius;
}
class Draw { //内部类
public void drawSahpe() {
System.out.println(radius); //访问外部类的private成员
System.out.println(count); //访问外部类的静态成员
}
}
}
同名成员变量或方法处理
当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量 外部类.this.成员方法
外部类访问内部类
虽然成员内部类可以无条件地访问外部类的成员,而外部类想访问成员内部类的成员却不是这么随心所欲了。在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问:
class Circle {
private double radius = 0;
public Circle(double radius) {
this.radius = radius;
getDrawInstance().drawSahpe(); //必须先创建成员内部类的对象,再进行访问
}
private Draw getDrawInstance() {
return new Draw();
}
class Draw { //内部类
public void drawSahpe() {
System.out.println(radius); //外部类的private成员
}
}
}
成员内部类是依附外部类而存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。创建成员内部类对象的一般方式如下
public class Test {
public static void main(String[] args) {
//第一种方式:
Outter outter = new Outter();
Outter.Inner inner = outter.new Inner(); //必须通过Outter对象来创建
//第二种方式:
Outter.Inner inner1 = outter.getInnerInstance();
}
}
class Outter {
private Inner inner = null;
public Outter() {
}
public Inner getInnerInstance() {
if(inner == null)
inner = new Inner();
return inner;
}
class Inner {
public Inner() {
}
}
}
补充:
内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。比如上面的例子,
如果成员内部类Inner用private修饰,则只能在外部类的内部访问,
如果用public修饰,则任何地方都能访问;
如果用protected修饰,则只能在同一个包下或者继承外部类的情况下访问;
如果是默认访问权限,则只能在同一个包下访问。这一点和外部类有一点不一样,外部类只能被public和包访问两种权限修饰。我个人是这么理解的,由于成员内部类看起来像是外部类的一个成员,所以可以像类的成员一样拥有多种权限修饰
局部内部类
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内
注意,局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的
class People{
public People() {
}
}
class Man{
public Man(){
}
public People getWoman(){
class Woman extends People{ //局部内部类
int age =0;
}
return new Woman();
}
}
静态内部类
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter.Inner();
}
}
class Outter {
public Outter() {
}
static class Inner {
public Inner() {
}
}
}
匿名内部类()
没有名称的内部类
常用于 Swing程序设计中 事件监听处理
常用来创建接口的唯一实现类
常用来创建某个类的唯一子类
特点:
- 可以继承父类的方法,重写父类的方法
- 可以访问外嵌类中的成员变量和方法,在匿名类中不能声明 静态变量 和静态方法
- 使用匿名类时,必须在某个类中直接使用匿名类创建对象
- 在使用匿名类创建对象时,要直接使用父类的构造方法
转载备注出处