Java学习—day07
简介:
在java
中存在继承的思想,来提高代码的复用性,代码的拓展性。
程序中的继承,是类与类之间的特征和行为的一种赠予或获取。一个类可以将自己的属性和方法赠予其他的类,一个类也可以从其他的类中获取他们的属性和方法。
两个类之间的继承,必须满足is a 的关系
两个类之间,A类将属性和特征赠予B类。此时A类被称为是父类,B类被称为是子类,两者之间的关系是子类继承自父类。
final关键字
**定义:**在程序中只要被final修饰的内容是不能再被改变的。
int a = 5; //这是定义了一个int型的变量a 赋值成5。如果我们给它加上修饰词final
final int a = 5; //这里a就相当于变成了常量,值一直是5,不能在被改变
可以修饰的内容:
- 类:final修饰的类不能有子类
- 成员变量:变量是一个终值,不能再被改变。所以在定义时必须先手动给一个值。
- 局部变量:被final修饰的局部变量是一个终值,不能再被改变
- 方法:final修饰的方法不允许重写
public class Demo6 {
public static void main(String[] args) {
Animal animal = new Animal();
//name是常量,值不能改变.
//animal.name = "chen";
}
}
//1.类:final修饰的类不能有子类,外界只能用不能改
//final class Animal{
class Animal{
//2.成员变量:变量是一个终值,不能再被改变.所以在定义时必须先手动给一个值.
final String name = "bing";
//4.方法:final修饰的方法不允许重写
public final void show(){
//3.局部变量:被final修饰的局部变量是一个终值,不能再被改变
final int a = 4;
//a++;
System.out.println(a);
}
}
空白final【了解】
- 描述:修饰成员变量的一种形式
- 如果是自定义的类可以在定义时先不给值,但是必须在构造方法中给值,即必须保证属性时被初始化了的,这种情况叫空白final
- 优点:空白final在final的使用上提供了更大的灵活性,因为一个类中的final域可以做到根据对象而有所不同,却有保持其恒定不变的特性。
//接上面的代码
class Bird extends Animal{
//这里暂时没有赋值
final String model;
public Bird(String model){
this.model = model;//这里完成赋值
}
}
Object类【了解】
定义
Object类:是java
继承体系中所有类的父类,Object类没有父类。(包含11个方法,相当于所有子类都默认有这些方法)
继承
父类的抽取:
将多个具体的类中相同的属性和行为提取出来到一个类中。
继承的特点(重点)
- 产生继承关系后,子类可以使用父类中的属性和方法,也可以定义子类独有的属性和方法
- Java是单继承,一个类有且只有一个直接的父类,可以有若干个间接的父类,一个父类可以有0个或多个子类,子类之间互不影响
- 使用继承,可以简化代码,提高代码的复用性,提高代码的拓展性,增加代码的健壮性,最重要的使类与类之间产生了继承的关系,是多态的前提
继承的语法
- 继承,需要使用关键字extends,在定义类的时候,使用子类extends父类的方式描述继承
- Object类:是Java继承体系中所有类的父类,Object类没有父类。
/Phone类没有显示的父类,默认父类是Object类
class Phone {}
//Iphone类继承自Phone类
class Iphone extends Phone {
}
不可以被继承
- 构造方法
- 构造方法是为了创建当前类的对象的,不可以继承给子类
- 私有成员
- 私有成员只能在当前的类中使用,不可以继承给子类
- 注意:父类的私有成员,在子类中可见不可用
- 跨包子类
- 默认的权限属性、方法,不可以继承给跨包子类
访问权限修饰符
访问权限修饰符,就是修饰类、属性的访问级别
当前类 | 同包其他类 | 跨包子类 | 跨包其他类 | |
---|---|---|---|---|
private | √ | × | × | × |
default(不能写出, 不写权限, 默认就是这个权限) | √ | √ | × | × |
protected | √ | √ | √ | × |
public | √ | √ | √ | √ |
方法的重写【重点】
重写的原理
- 当子类希望实现父类方法的功能之外的一些功能是,如何处理?
解决:子类可以继承到父类中的属性和方法,但是有些方法,子类的实现与父类的方法可能实现的不同。当父类提供的方法已经不能满足子类的需求时,子类中可以定义与父类相同的方法。
- 当出现同名方法后,方法如何调用?
子类方法完成了对父类方法的覆盖,又叫重写(Override)
class Phone extends Object{
String color;
int model;
public void callPhone(){
System.out.println("打电话");
}
public void show(){
return null;
}
}
class Iphone extends Phone{
String gui;
public void fangShui(){
System.out.println("防水");
}
@Override
public void callPhone(){
//公共的功能
//System.out.println("打电话");
//通过super调用父类的callPhone方法
super.callPhone();
//自己的功能
System.out.println("自己的功能");
}
//父类返回值是Phone,子类的show返回值是Iphone,重写时,程序允许返回值不同
//重写的注意点:父类和子类的重写方法返回值可以不同,但是方法名,参数必须相同.返回值不同时,
//必须保证父子类的重写方法的返回值有继承关系,并且子类中的返回值的类型是父类的返回值类型或者子类类型
//在同一个类中不允许出现方法名,参数都相同,但是返回值不同的情况.
public Iphone show(){
return null;
}
}
@Override
一个注解,进行重写前的检验这个方法是否是开一个重写的方法。如果不是重写的方法,会直接报错。
重写的注意事项
- 方法名字必须和父类方法名字相同
- 参数列表必须和父类一致
- 子类方法的访问权限需要大于等于父类的方法的访问权限,父类不能是private
- 子类方法的返回值类型需要小于等于父类方法的返回值类型–这里说的是引用类型
super关键字
- 有时候,子类重写父类方法的时候,并不是要对父类的实现全盘推翻,而是对父类方法进行拓展
- 父类方法中的实现仍然需要,但是还需要在父类方法的基础上进行拓展的实现,此时就需要使用super关键字调用父类的方法
- this和super的对比
- this:是一种引用类型,代表当前对象,保存的是当前对象的地址
- super:代表的是当前对象的父类,可以调用父类的成员,但是他不是引用数据类型
class Student {
public void work() {
System.out.println("学生在学习");
}
}
class Monitor extends Student {
@Override
public void work() {
super.work(); // 调用父类的实现
System.out.println("班⻓收作业");
}
}
继承中使用构造方法【重点】
基本使用:
- 子类对象还实例化的时候,需要先实例化从父类继承到的部分。此时通过super()默认调用父类中的无参构造方法。
-
ps:
super()方法是默认的,不需要显示写出来
class Animal {
public Animal() {
System.out.println("父类中的构造方法执行");
}
}
class Dog extends Animal {
public Dog() {
//这里不显示写,也会默认有super(),调用的是父类的空参构造方法
super();
System.out.println("子类中的构造方法执行");
}
}
- 当我们创建构造方法的时候,为什么一定要调用super?
原因:父类中也有属性要进行初始化,而对象的属性必须由自己的构造方法进行初始化,所以必须调用super(),所以每个构造方法中都默认有一个super()
- 如果父类中没有无参构造方法,对所有的子类对象实例化都会造成影响,导致子类对象无法实例化
(类中没有无参构造方法的情况:当我们在类中只写了有参构造方法时,系统不会再自动创建无参构造方法)
解决方案:
1.给父类添加无参构方法
2.在子类的构造方法中,使用super(参数列表),调用父类中的有参构造方法
总结:在继承体系中,作为父类最好的办法就是将无参构造方法和有参构造方法都写了
class Animal {
String name;
int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
//1.给父类添加无参构造方法。
public Animal(){
}
}
class Dog extends Animal {
public Dog(String name, int age) {
super(name, age); // 2.调用父类中存在的构造方法,实例化父类部分
}
}
注意:
为什么要将super放在构造方法的第一行?
在子类的构造方法中有可能用到父类的属性,而属性在使用之前必须先进行初始化,否则无法使用。super的作用是初始化父类的属性,如果在super之前调用了其他的代码,有可能造成在未对父类属性初始化时使用了属性的错误情况发生,所以系统默认super前面不能放任何代码,this()用于构造方法调用时也要放在第一行是一个道理。
class Animal{
String name;
//public Animal(){}
public Animal(String name){
super();
this.name = name;
}
}
class Dog extends Animal{
public Dog(){
//super前不能写任何代码
//System.out.println();
super("bing");
}
}
类与类之间的关系
共三种
1.继承---描述:谁是谁 例:人是动物
2.组合---描述:谁属于谁 例:狗属于人/人拥有狗
3.传参
//创建测试类
public class Demo7 {
//人有一只狗
public static void main(String[] args) {
Person per = new Person();
per.name = "张三";
per.dog = new Dog("拉布拉多");
}
public static void feedDog(Dog dog){//传参
dog.eat();
}
}
//创建的人类
class Person{
String name;
Dog dog;//组合
}
//创建动物类
class Animal{
String name;
}
//创建狗类
class Dog extends Animal{//继承
String name;//组合
public Dog(String name){
this.name = name;
}
public void eat(){
System.out.println("吃⻣头");
}
}