面向对象高级(继承,重写,重载,抽象类,多态接口,内部类,递归)

面向对象高级

🌟继承
结构:
class 父类 {

}

class 子类 extends 父类 {
super( ); //调用了父类所有的属性和方法
}

✨super的用法:
/*Java的继承机制:

  • Java中只用单继承,多重继承(爷爷,父亲,子),没有多继承(一个孩子多个爹)
  • super:在子类中,Super就表示自动被创建的父类对象,子类创建多少个,就会自动创建多少个父类对象
  • 通过super ,可以访问父类的构造方法
  •  调用super 构造方法的代码,必须写在子类构造方法的第一行
    

通过super ,可以访问父类的构造方法
调用super 构造方法的代码,必须写在子类构造方法的第一行,而this( )调用方法也要写在第一行,既调用this( ),又调super( )是不合法的,所以要么调用this( )方法,在this( )方法中调用super( )继承,要么调用super( )不调用其他的构造方法了。

  • 通过super,可以访问父类的属性
  • 通过super,可以访问父类的方法

在这里插入图片描述

🌟重写override 重写与重载的区别
子类从父类继承了很多方法,某些方法子类还想有与父类不一样的规则,可以将父类这一方法在子类中再编写一遍
✨重写override的规则:
1.参数列表必须完全与被重写方法的参数列表相同
正确重写方法:

public static void main(String[] args){
Student s = new Student();
s.say();
}

class Person{
public void say(){
System.out.println(“锄禾日当午,汗滴禾下土”);
}
}

class Student{
public void say(){
System.out.println(“哈哈哈哈哈哈”); //s.say(); 打印哈哈哈哈哈哈
}

}

错误写法:
class Student{
public void say(String text){ //❌ 参数列表必须完全与被重写方法的 参数列表相同
System.out.println(“哈哈哈哈哈哈”) //s.say(); 打印锄禾日当午…
}
}

2.返回类型必须完全与被重写方法的返回类型相同
3.访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为public, 那么在子类中重写该方法就不能声明为protected 或者 private 或者 默认default

在这里插入图片描述

4.父类的成员方法只能被它的子类重写
即两个类必须有继承关系才能重写,如果两个类没关系则不能重写

5.声明为static 和 private 的方法不能被重写,但是能够被再次声明
静态方法本身跟对象没有关系

✨重载
构造方法的重载和普通方法的重载
🚩面试官常问题:
Java中重写和重载的区别:
1.发生位置
重写override是发生在子父类中,子重写父的方法中
重载overload发生在一个类里面
2.参数列表限制
重写override:参数列表必须相同
重载overload:参数列表必须不同
3.返回值类型:
重写override:返回值类型必须一致
重载overload:与返回值类型无关
4.访问权限:
重写override:子的方法权限必须小于父的方法权限
重载overload:与反问权限无关
5.异常处理:

重写:异常范围更小,但是不能抛出新的异常
重载:与异常无关

🌟final关键字:
1.final 用于修饰属性、变量:
变量变成了常量,只可以赋值一次,无法对其再次赋值
final 修饰的局部变量,只能赋值一次(可以先声明后赋值)
final 修饰的是成员属性,必须在声明时赋值。

✨全局常量(public static final):这个常量可以被任何位置通过类名. 直接使用
final 表示不可改变,是一个常量
static 表示可以通过类名直接去访问它
public 表示整个工程中任何位置都可以访问到它,访问权限是最大的

✨常量和全局常量的命名规范:
由一个或多个单词组成,单词与单词之间使用下划线隔开,单词所有字母大写

2.final 用于修饰类:
final修饰的类,不可以被继承
3.final 用于修饰方法:
final修饰的方法,不能被子类重写

🌟抽象类:一个类中如果含抽象方法,即有不确定的方法,我们称之为抽象类
abstract class 类名{

}

1.不能被实例化(无法通过抽象的图纸进行实物的描述),即不能使用关键字 new 完成
2.如果想要实例化必须被子类所继承,在子类方法中重写override抽象类不明确的方法,如果抽象类没有被继承,编写这个抽象类是没有意义的

抽象方法:无大括号的方法

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

⚠️抽象类常见问题
1.抽象类不能直接创建对象,不能 new 实例化
2.使用final声明,最终的,不能拥有子类,不能被继承
🚩面试问题:抽象类能否有构造方法?
能有构造方法,它不能被我们创建,但是能被JVM虚拟机自动创建,而子类对象实例化的时候的流程与普通类是一样的,都是要先调用父类中的构造方法(默认是无参的),之后再调用子类自己的构造方法。

✨抽象类和普通类的区别
1.抽象类必须用public 或 protected 修饰(如果被private修饰,子类无法继承它,也无法实现其抽象方法),不写标识符默认为public,不存在默认default 的效果
2.抽象类不可以使用new关键字创建对象,但是在子类创建对象时,抽象父类也会被JVM实例化
3.如果一个子类继承抽象类,那么必须实现其所有的抽象方法,如果有为实现的抽象方法,那么子类也必须定义为abstract 抽象类

🌟接口

1.成员变量其实是常量,格式:
[public] [static] [final] 数据类型 常量名称 = 数据值;
注意:
常量必须进行复制,而且一旦赋值不能改变
常量名称完全大写,用下划线进行分隔

2.接口中最重要的就是抽象方法,格式:
[public] [abstract] 返回值类型 方法名称(参数列表);
注意:实现类必须覆盖重写接口所有的抽象方法,除非实现类是抽象类

3.从Java 8开始,接口里允许定义默认方法,格式:
[public] default 返回值类型 方法名称(参数列表){ 方法体 }
注意:默认方法也可以被覆盖重写

4.从Java 8 开始,接口里允许定义静态方法,格式:
[public] static 返回值类型 方法名称(参数列表){ 方法体 }
⚠️注意:应该通过接口名称进行调用,不能通过实现类对象调用接口静态方法

5.从Java 9 开始,接口里允许定义私有方法,格式:
普通私有方法:private 返回值类型 方法名称(参数列表){ 方法体 }
静态私有方法:private static 返回值类型 方法名称 (参数列表){ 方法体 }
⚠️注意:private 的方法中有接口自己才能调用,不能被实现类或别人使用。

设置接口格式:
interface 接口名称{
全局常量;//public static final
抽象方法;//没有大括号的方法
}

✨接口实现: implements
Class 子类 implements 父接口1,父接口2…{

}
一个类既要实现接口,又要继承抽象类,要按照以下的格式编写:
class 子类 extends 父类 implements 父接口1,父接口2…{

}

✨接口的继承:
接口因为都是抽象部分,不存在具体的实现,所以允许多继承,例如:
interface C extends A,B {

}
⚠️如果一个接口要想使用,必须依靠子类。子类(如果不是抽象类的话)要实现接口中的所有抽象方法。

✨面向接口的思想:
接口是定义(规范,约束)与实现的分离。建议在编写程序项目时,先写接口。
优点:
1.降低程序的耦合性(模块与模块之间的粘度,在某一模块代码被替换时其他代码能够正常运行)
2.易于程序的扩展(某一模块升级)
3.有利于程序的维护

🌟接口和抽象类的区别:
1.抽象类要被子类继承,接口要被子类实现
2.接口只能声明抽象方法,抽象类中可以声明抽象方法,也可以写非抽象方法
3.接口里定义的变量只能是公共的静态常量,抽象类中的变量是普通变量
4.抽象类使用继承来使用,无法多继承。接口使用实现来使用,可以多实现
5.抽象类中可以包含static 方法,但是接口中不允许(静态方法不能被子类重写,因此接口中不能声明静态方法)
6.接口不能有构造方法(接口中的子类在创建时,接口不会创建对象),但是抽象类可以有

🌟多态
面向对象的三大特性:封装性,继承性,多态性
extends 继承或者 implements 实现,是多态性的前提
小明既有学生的形态,又有人类的形态,这就是对象的多态性。

代码中多态格式的使用:
代码中体现多态性,其实就是 父类引用指向子类对象
左父右子,体现了面向对象的多态性
格式:
父类名称 对象名 = new 子类名称();
或者:
接口名称 对象名 = new 实现类名称();

下面是两个多态的例子,通过例子更容易理解多态的概念

在这里插入图片描述

在这里插入图片描述

🌟instanceof
实例化对象 instanceof 类,在条件语句中表示左边对象是否是右边的实例
if(o instanceof Vector){
}

🌟Object 类:表示万物
object 类可以接受任何数据

🌟API 的使用

🌟toString
放在类里,用来自定义,从而更加详细描述类的特征,如:
public static void main(String[] args){
Person p1 = new Person(“张三”,18);
System.out.println(p1);
Person p2 = new Person(“李四”,18);
System.out.println(p2);
}

public person {
public String toString() {
return “这是一个人,这个人的姓名是:”+this.name+,这个人的年龄是:”+this.age;
}
}

🌟equals
== 用于比较两个对象开辟的堆空间内存中的地址值是否相等(不可能相等)

用于比较两个对象是否相等

Person p1 = new Person();
Person p2 = new Person();

Systemm.out.println(p1.equals(p2));
结果依然不相等,因为是
public boolean equals(Object obj){
return (this == obj); //Object是万物的父类
}

在这里插入图片描述

🚩面试问:
equals方法重写时的五个特性:
自反性 :对于任何非空的参考值x , x.equals(x)应该返回true 。
对称性 :对于任何非空引用值x和y , x.equals(y)应该返回true当且仅当y.equals(x)回报true 。 传递性 :对于任何非空引用值x , y和z ,如果x.equals(y)回报true个y.equals(z)回报true ,然后
x.equals(z)应该返回true 。
一致性 :对于任何非空引用值x和y ,多次调用x.equals(y)始终返回true或始终返回false ,前提是未修改对象
上的equals比较中使用的信息。
非空性 :对于任何非空的参考值x , x.equals(null)应该返回false 。

🌟内部类
定义在一个类的内部的类叫成员内部类,包括:
1.成员内部类:只有外部类创建了对象才可以使用
成员内部类可以无条件地使用外部类的所有成员属性和成员方法(包括private 成员和静态成员)

Outer outer = new Outer();
Outer.Inner i = o.new Inner();

在这里插入图片描述

2.局部内部类
局部内部类是在定义一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内部或者该作用域内。

⚠️注意:局部内部类就像是方法里面的一个局部变量一样,是不能有public, protect, private, 以及static 修饰符的

在这里插入图片描述

3.匿名内部类
只使用一次的类,和局部内部类很像,属于局部内部类的一种,局部内部类的限制对匿名内部类都生效。但是匿名内部类没有名字,所以创建方式有点奇怪,格式如下:
new 父类构造器(参数列表) / 实现接口()
{
//匿名内部类
}

在这里插入图片描述

⚠️注意:

🚩面试问题:为什么局部内部类和匿名内部类只能访问final型局部变量/为什么变量前一定要加final?

因为局部内部类或匿名内部类会被单独地编译成一个字节码文件,为了保证这个单独的文件中为变量做的备份的值与内部类外面的变量值绝对是一致的,系统从规则上限制了这个值不可更改。

4.静态内部类
和成员内部类很像,多加了一个static
与成员内部类不同,无需创建外部类对象,再创建内部类对象,可以直接创建静态内部类对象,如:
public static void main(String[] args){
Book.Info info = new Book.Info();
info.say(); //方法的调用直接 静态类名.方法名()就可以调用。
}

⚠️注意:静态内部类不能访问外部类中非静态的资源

🌟包装类
装箱:把一个基本数据类型变为包装类
拆箱:把一个包装类变为一个基本数据类型

💥重要:
包装类Integer,Short,Long,Double,Float,Byte都是Number的子类,表示一个数字,需要记住Number 这个父类的方法

包装类Character,Boolean都是Object的子类

JDK 1.5 之后有
自动装箱:
Integer i = 200; //把一个整数200装箱为一个类

自动拆箱:
int j = i; //把一个类拆箱为一个整数

✨字符串的转换:💥
包装类还可以将一个字符串转变为指定的基本数据类型,一般用在接收数据上使用较多:
在八个包装类中提供了以下操作方法:
public static int parseInt(String s) :将String变为int型数据
public static float parseFloat(String s):将String变为Float
public static boolean parseBoolean(String s):将String变为boolean
… …
在这里插入图片描述

🌟可变参数:
当不知道要传入多少个参数的时候,或者需要自动传入任意个数的时候,可以用可变参数,⚠️注意:可变参数必须置于参数列表的最后
语法:
返回值类型 方法名称(数据类型…参数名称){
//参数在方法内部,以数组的形式来收取
}

public static void main(String[] args){
System.out.println(sum());
System.out.println(sum(1,2,3));
System.out.println(sum(1,2,3,4));
System.out.println(sum(1,2,3,4,5));
}

public static void haha(String x, int…y){
//规定参数列表中可变参数的位置必须要放在其他所有参数的后面
}

public static int sum(int…nums) {
int n = 0;
for(int i =0;i<nums.length;i++){
n+=nums[i];
}
return n;
}

🌟递归
在方法的定义中使用方法自己。递归的算法是一种直接或间接调用自身方法的算法。

在这里插入图片描述

🌟递归实现阶乘
5的阶乘:54321 5乘以4的阶乘
程序中能使用循环尽量不要使用递归,效率低,方法入栈,栈内存容易溢出

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值