面向对象高级

tech2022-08-09  144

继承

概述

继承是面向对象三大特征之一。 继承就是子类继承父类的特征(属性)和行为(方法),使得子类对象具有父类的实例域和方法,或类从父类继承方法,使得子类具有父类相同的行为。还可以在子类中重新定义,追加属性和方法

格式

格式:public class 子类名 extends 父类名{ } 范例:public class Zi extends Fu{ }

特点

子类可以有父类的内容子类还可以有自己特有的内容

好处和弊端

好处: 提高了代码的复用性(多个类相同可以放到同一个类中) 提高了代码的维护性(如果方法的代码需要修改,修改一处即可) 弊端: 继承让类与类之间产生了关系。类的耦合性增强了,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性

什么时候使用?

继承体现的关系:is a 假设法:有两个类A和B,如果满足A是B的一种或B是A的一种,就说明他们存在继承关系,这个时候就可以考虑使用继承来体现,否则就不能滥用

super

super关键字与this关键字:

this:代表本类对象的引用(this关键字指向调用该方法的对象,一般我们是在当前类中使用this关键字,所以常说this代表本类对象的引用)super:代表父类存储空间的标识(可理解为父类对象引用) 关键字访问成员变量访问构造方法访问成员方法thisthis.成员变量 访问本类成员变量this(…) 访问本类构造方法this.成员方法(…) 访问本类成员方法superthis.成员变量 访问本类成员变量this(…) 访问本类构造方法this.成员方法(…) 访问本类成员方法

变量访问特点

在子类方法中访问一个变量:

子类局部范围找子类成员范围找父类局部范围找如果都没有就报错(不考虑父类的父类)

构造方法访问特点

子类中所有的构造方法默认都会访问父类中无参的构造方法 例:

public class Fu { public Fu(){ System.out.println("Fu类无参构造方法被调用"); } public Fu(int age){ System.out.println("Fu类带参构造方法被调用"); } } public class Zi extends Fu{ public Zi(){ System.out.println("Zi类无参构造方法被调用"); } public Zi(int age){ System.out.println("Zi类带参构造方法被调用"); } } public class Demo { public static void main(String[] args) { //无参 Zi z = new Zi(); //带参 Zi z1 = new Zi(20); } }

运行结果: 为什么?

因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化每一个子类构造方法的第一条语句默认都是:super() public class Zi extends Fu{ public Zi(){ super();//一般不写,系统自带 System.out.println("Zi类无参构造方法被调用"); } public Zi(int age){ super(); System.out.println("Zi类带参构造方法被调用"); } }

跟上例运行结果相同 若Fu类没有无参构造方法,子类则需要访问带参构造方法或手动在Fu类添加无参构造方法(推荐使用这种)

public class Zi extends Fu{ public Zi(){ super(20); System.out.println("Zi类无参构造方法被调用"); } public Zi(int age){ super(20); System.out.println("Zi类带参构造方法被调用"); } }

运行结果:

成员方法访问特点

通过子类对象访问一个方法:

子类成员范围找父类的成员范围找如果都没有就报错(不考虑父亲的父亲…)

super内存图

例:

继承限制(注意事项)

Java中只有单继承,多重继承,没有多继承

方法重写

概述

子类中出现了和父类一模一样的方法声明

规则

1、参数列表必须完全与重写方法相同; 2、返回类型必须完全与被重写方法的返回值类型相同; 3、访问权限不能比父类中被重写的方法的访问权限更低; 4、父类的成员方法只能被它的子类重写; 5、声明为static和private的方法不能被重写,但是能够被再次声明。

应用

当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样既沿袭了父类的功能,又定义了子类特有的内容

Override

是一个注解可以帮助我们检查重写方法声明的正确性

方法重写注意事项

私有方法不能被重写(父类私有成员子类不能继承)子类方法访问权限不能更低(public>默认>私有)

重写与重载的区别

重载重写发生位置一个类中子父类中参数列表限制必须不同的必须相同的返回值类型与返回值类型无关返回值类型必须一致访问权限与访问权限无关子的方法权限必须不能小于父的方法权限异常处理与异常无关异常范围可以更小,但不能抛出新的异常

final

概念

final关键字是最终的意思,可以修饰成员方法,成员变量,类

特点

修饰方法:表明该方法是最终方法,不能被重写 修饰变量:表明该变量是常量,不能再次被赋值 修饰类:表明该类是最终类,不能被继承

final修饰局部变量

final修饰基本类型变量

final修饰指的是基本类型的数值不能发生改变 例:

public static void main(String[] args) { //final修饰基本类型变量 int age = 20; age = 100; System.out.println(age); }

运行结果为:100 用final修饰后: 重新赋值会报错,不能再被赋值

final修饰引用类型变量

final修饰指的是引用类型的地址值不能发生改变,但地址里面的内容是可以发生改变的 例:

public class Student { public int age = 20; } public static void main(String[] args) { //final修饰引用类型变量 final int age = 20; com.test5.Student s = new Student(); System.out.println(); }

运行结果为:100 加上final修饰后:

public static void main(String[] args) { final Student s = new Student(); s.age = 100; System.out.println(s.age); }

也没有报错,因为改变的是地址值

s = new Student();//加上这一句就会报错,因为改变了地址值

抽象类

抽象方法

只声明而未实现的方法称为抽象方法(未实现指的是:没有“{}”方法体),抽象方法必须使用abstract关键字声明。

抽象类概念

在Java中,一个没有方法体的方法应该定义为抽象法方法,而类中如果有抽象方法,该类必须定义为抽象类。

格式

public abstrac class 类名{ // 抽象类 public abstract void 方法名();//抽象方法,只声明而未实现 }

特点

抽象类和抽象方法必须使用abstract关键字修饰抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类抽象类不能实例化(不能直接使用关键字new完成) 抽象类如何实例化?参照多态的方式,通过子类对象实例化,这叫抽象类多态抽象类的子类 要么重写抽象类中的所有抽象方法 要么是抽象类

成员特点

成员变量 可以是变量 也可以是常量(也就是用final修饰的变量) 注:抽象类不能使用final声明,因为final属修饰的类是不能有子类的,而抽象类必须有子类才有意义构造方法 有构造方法,但不能实例化 构造方法的作用是什么?用于子类访问父类数据的初始化成员方法 可以有抽象方法:限定子类必须完成某些动作 也可以有非抽象方法:提高代码复用性

抽象类和普通的区别

1、抽象类必须用public或protected修饰(如果为private修饰,那么子类则无法继承,也就无法实现其抽象方法)。默认为 public

2、抽象类不可以使用new关键字创建对象, 但是在子类创建对象时,抽象父类也会被JVM实例化。

3、如果一个子类继承抽象类,那么必须实现其所有的抽象方法。如果有未实现的抽象方法,那么子类也必须定义为abstract类

接口

概述

接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用 Java中的接口更多的体现在对行为的抽象 如果一个类中的全部方法都是抽象方法,全部属性都是全局常量,那么此时就可以将这个类定义成一个接口

格式

** public interface 接口名称{ 全局常量 ; 抽象方法 ; }**

特点

接口用关键字interface修饰 public interface 接口名{}类实现接口用implements表示 public class 类名 implement 接口名{}接口不能实例化 接口如何实例化?参照多态的方式,通过实现类对象实例化,这叫接口多态接口实现类 要么重写接口中的所有抽象方法 要么是抽象类

成员特点

成员变量 只能是常量 默认修饰符:public static final构造方法 接口没有构造方法,因为接口主要是对行为进行抽象的,是没有具体存在 一个类如果没有父类,默认继承自Object类成员方法 只能是抽象方法 默认修饰符:public abstract

类、接口、抽象类

类与接口的关系

类和类的关系 继承关系,只能单继承,但是可以多层继承类和接口的关系 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口接口和接口的关系 继承关系,可以单继承,也可以多继承

抽象类和接口区别

1、抽象类要被子类继承,接口要被类实现。

2、接口只能声明抽象方法,抽象类中可以声明抽象方法,也可以写非抽象方法。

3、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。

4、抽象类使用继承来使用,无法多继承。接口使用实现来使用,可以多实现

5、抽象类中可以包含static方法 ,但是接口中不允许(静态方法不能被子类重写,因此接口中不能声明静态方法)

6、接口不能有构造方法,但是抽象类可以有。

7、抽象类是对事物的抽象,而接口是对行为的抽象

多态

概念

同一个对象,在不同时刻表现出来的不同形态

前提和体现

有继承/实现关系有方法重写有父类引用指向子类对象

成员访问特点

成员变量:编译看左边,执行看左边成员方法:编译看左边,执行看右边 为什么成员变量和成员方法的访问不一样? 因为成员方法有重写,而成员变量没有

好处和弊端

多态的好处:提高了程序的扩展性 具体体现:定义方法的时候,使用父类型作为参数,将来使用的时候,使用具体的子类型参与操作多态的弊端:不能使用子类的特有功能

转型

向上转型:将子类实例变为父类实例 格式:父类 父类对象 = 子类实例 ; 例:Animal a = new Cat();向下转型:将父类实例变为子类实例 格式:子类 子类对象 = (子类)父类实例 ; 例:Cat c = (Cat)a;

多态形式

①具体类多态 ②抽象类多态 ③接口多态

形参和返回值

类名作为形参和返回值

方法的形参是类名,其实需要的是该类的对象方法的返回值是类名,其返回值是该类的对象 例: public class Cat { public void eat(){ System.out.println("猫吃鱼"); } } public class CatOperate { public void useCat(Cat c){ c.eat(); } public Cat getCat(){ Cat c = new Cat(); return c; } } public static void main(String[] args) { CatOperate co = new CatOperate(); Cat c = new Cat(); co.useCat(c); Cat c2 = co.getCat(); c2.eat(); }

抽象类名作为形参和返回值

方法的形参是抽象类型,其实需要的是该抽象类的子类对象方法的返回值是抽象类名,其实返回的是该抽象类的子类对象 例: public abstract class Animal { public abstract void eat(); } public class AnimalOperate { public void useAnimal(Animal a){ a.eat(); } public Animal getAnimal(){ Animal a = new Cat(); return a; } } 在这里插入代码片public static void main(String[] args) { AnimalOperate ao = new AnimalOperate(); Animal a = new Cat(); ao.useAnimal(a); Animal a2 = ao.getAnimal(); a2.eat(); }

抽象类接口名作为形参和返回值

方法的形参是接口名,其实需要的是该接口的实现类对象方法的返回值是接口名,其实返回的是该接口的实现类对象

instanceof

作用

判断某个对象是否是指定类的实例,则可以使用instanceof关键字( 判断传入的对象是哪个子类的对象)

格式

实例化对象 instanceof 类 //此操作返回boolean类型的数据

Object

①在java.lang包下,不需要导包 ②Object类是所有类的父类(基类),如果一个类没有明确的继承某一个具体的类,则将默认继承Object类。 ③使用Object可以接收任意的引用数据类型 ④构造方法(只有无参):

构造方法描述Object()构造一个新对象

⑤方法(主要使用):

方法名描述toString返回对象的字符串表示形式equals(Object obj)指示一些对象是否等于此

toString

返回对象的字符串表示形式。一般来说,toString方法返回一个“toString代表”这个对象的字符串。结果应该是一个简明扼要的表达,容易让人阅读。建议所有子类覆盖此方法。

equals

方法名说明public boolean equals(Object obj)比较对象是否相等。默认比较地址,重写可以比较内容,自动生成

equals方法重写的五个特性:自反性、对称性、传递性、一致性、非空性

API

概念

API(Application Programming Interface):应用程序接口 Java API:指的是JDK中提供的各种功能的Java类

API的使用

查看源码

选中,然后Ctrl+鼠标左键,(IDEA用Ctrl+B也可以)

使用中文API文档

使用下图文档步骤: ①右键打开该文档 ②找到索引选项卡中的输入框 ③在输入框中输入要查找的内容 ④看类在哪个包下(java.lang包是不需要导包的) ⑤看类的描述 ⑥看构造方法 ⑦看成员方法

内部类

概念

就是在一个类或方法里面定义另一个类 一般包括四种: ①成员内部类 ②局部内部类 ③匿名内部类 ④静态内部类

格式

public class 类名{ 修饰符 class 类名{ } }

访问特点

内部类可以直接访问外部类的成员,包括私有外部类要访问内部类的成员,必须创建对象

成员内部类

如何创建对象? 格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象 例:Outer.Inner oi = new Outer().new Inner(); 直接使用(例):

public class Outer { private int num = 10; public class Inner{ public void show(){ System.out.println(num); } } } public static void main(String[] args) { Outer.Inner oi = new Outer().new Inner(); oi.show(); }

间接使用(常用):

public class Outer { private int num = 10; private class Inner{ public void show(){ System.out.println(num); } } public void method(){ Inner i = new Inner(); i.show(); } } public static void main(String[] args) { Outer i = new Outer(); i.method(); }

注意: 当成员内部类拥有和外部类同名的成员变量或方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员,需要以下面的形式进行访问: 外部类.this.成员变量 外部类.this.成员方法

局部内部类

局部内部类是在方法或作用域中定义的类,所以外界是无法直接使用,需要在方法内部创建对象并使用 该类可以直接访问外部类的成员,也可以访问方法内部的局部变量 例

public class Outer { private int num = 10; public void method(){ int num2 = 20; class Inner{ public void show(){ System.out.println(num); System.out.println(num2); } } Inner i = new Inner(); i.show(); } } public static void main(String[] args) { Outer o = new Outer(); o.method(); }

匿名内部类

前提

存在一个类或接口,这里类可以是具体类也可以是抽象类

格式

new 类名或接口(){ 重写方法; }; 或者: new 父类构造器(参数列表) | 实现接口() { //匿名内部类的类体部分 } 其本质是一个继承了该类或实现了该接口的子类匿名对象 匿名内部类使用(单次)例:

public class Outer { private int num = 10; public void method(){ new Inter(){ public void show(){ System.out.println("匿名内部类"); } }.show(); } } public interface Inter { void show(); } public static void main(String[] args) { Outer o = new Outer(); o.method(); }

多次调用(只有Outer类改变,其他不变):

public class Outer { private int num = 10; public void method(){ Inter i = new Inter(){ public void show(){ System.out.println("匿名内部类"); } }; i.show(); i.show(); i.show(); } }

注意事项

1、使用匿名内部类时,我们必须是继承一个类或一个接口,但两者不也可兼得,同时只能继承一个类或实现一个接口 2、匿名内部类中是不能定义构造函数的 3、匿名内部类中不能存在任何的静态成员变量和静态方法 4、匿名内部类为局部内部类,所有局部内部类的所有限制同样对匿名内部类生效 5、匿名内部类不是是抽象的,它必须要实现继承的类或实现的接口的所有抽象方法 6、只能访问final型的局部变量

静态内部类

静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static 静态内部类是不需要依赖与外部类对象的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非静态成员或方法

包装类

概述

在Java中有一个设计原则“一切皆对象”,那么这样一来Java中的一些基本数据类型,就完全不符合这种设计思想,因为Java中的八种基本数据类型并不是引用数据类型,所以Java中为了解决这样的问题,引入了八种基本数据类型的包装类(将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据) 常用操作之一:用于基础数据类型与字符串之间的转换

基础数据类型包装类byteByteshortShortintIntegerlongLongfloatFloatdoubleDoublecharCharacterbooleanBoolean

以上的八种包装类也分为两种大的类型:

Number:Integer、Short、Long、Double、Float、Byte都是Number的子类表示是一个数字Object:Character、Boolean都是Object的直接子类

Integer

①在java.lang包下,不需要导包 ②Integer类包装一个对象中的原始类型int值。类型为Integer的对象包含一个单一字段,类型为int。此外,该类还提供了几种将int转换为String和String转换为int,以及其他常量和方法在处理int时非常有用 ③构造方法:

方法名说明public Integer(int value)根据int值创建Integer对象(过时)public Integer(String s)根据String值创建Integer对象(过时)public static Integer valueOf(String s)返回表示指定的int值的Integer实例public static Integer valueOf(String s)返回一个保存指定值的Integer对象String

装箱和拆箱

装箱:把基本数据类型转换为对应的包装类类型

/** * 装箱 */ //手动装箱(JDK1.5之前) Integer i = Integer.valueOf(100); //自动装箱(JDK1.5开始) Integer ii= 100;

拆箱:把包装类类型转换为对应的基本数据类型

/** * 拆箱 */ //手动拆箱(JDK1.5之前) ii = i.intValue()+200; //自动拆箱(JDK1.5开始) ii += 200; System.out.println(ii);

注意:在使用包装类类型的时候,如果做操作,最好先判断是否为null推荐的是只要是对象,在使用前就必须进行不为null的判断

int和String的相互转换

1、int转换为String public static String valueOf(int i):返回int参数的字符串表示形式。该方法是String类中的方法 2、String转换为int public static int parseInt(String s):将字符串解析为int类型。该方法是Integer类中的方法 例:

public static void main(String[] args) { //int --- String int num = 100; //方式1 String s1 = ""+num; System.out.println(s1); //方式2 //public static String valueOf(int i) String s2 = String.valueOf(num); System.out.println(s2); System.out.println("--------"); //String --- int String s = "100"; //方式1 //String --- Integer --- int Integer i = Integer.valueOf(s); //public int intValue() int x = i.intValue(); System.out.println(x); //方式2 //public static int parseInt(String s) int y = Integer.parseInt(s); System.out.println(y); }

可变参数

概念

一个方法中定义完了参数,则在调用的时候必须传入与其一一对应的参数,但在JDK1.5之后提供了新的功能,可以根据需要自动传入任意个数的参数

格式

返回值类型 方法名称(数据类型**…**参数名称){ //参数在方法内部,以数组的形式来接收 }

注意

可变参数只能出现在参数列表的最后

递归

在数学与计算机科学中,是指在方法的定义中使用方法自身,也就是说,递归算法是一种直接或间接调用自身方法的算法 递归解决问题的思路: 把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解 递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算 递归解决问题要找到两个内容:

递归出口:否则会出现内存溢出递归规则:与原问题相似的规模较小的问题
最新回复(0)