宠物猫类有一个特有的方法 sleep
,在方法中可以调用其父类 Pet
的 getName
方法。
调用类的方法:
// 实例化一个宠物狗
Dog dog = new Dog();
dog.setName(“张三”);
dog.setWeight(30f);
// 调用继承自父类的公有方法
dog.eat();
// 调用其特有方法
dog.run();
// 实例化一个宠物猫
Cat cat = new Cat();
cat.setName(“豆豆”);
// 调用继承自父类的公有方法
cat.eat();
// 调用其特有方法
cat.sleep();
运行结果:
张三在吃东西
胖成了30.0斤的狗子张三在奔跑
豆豆在吃东西
豆豆睡大觉zzz
3.1 概念
如果一个类从它的父类继承了一个方法,如果这个方法没有被标记为 final
或 static
,就可以对这个方法进行重写。重写的好处是:能够定义特定于子类类型的行为,这意味着子类能够基于要求来实现父类的方法。
3.2 实例
在上述父类 Pet
中有一个 shout
方法,我们知道小猫和小狗的叫声是不同的,此时可以使用方法重写,在 Dog
类和 Cat
类中重写 shout
方法。
Dog 类:
class Dog extends Pet{
// 重写 shout 方法
public void shout() {
System.out.println(this.getName() + “汪汪汪地叫~”);
}
}
Cat 类:
class Cat extends Pet{
@Override // 使用注解
public void shout() {
System.out.println(this.getName() + “喵喵喵地叫~”);
}
}
Tips:在要重写的方法上面,可以选择使用
@Override
注解,让编译器帮助检查是否进行了正确的重写。如果重写有误,编译器会提示错误。虽然这个注解不是必须的,但建议日常编码中,在所有要重写的方法上都加上@Override
注解,这样可以避免我们由于马虎造成的错误。
在IDEA里只要和父类方法名一致,就会自动生成
@Overvide
修饰符,意思是对父类的方法进行重写
可以使用对象实例调用其重写的方法:
// 实例化一个宠物狗
Dog dog = new Dog();
dog.setName(“欢欢”);
// 调用重写方法
dog.shout();
// 实例化一个宠物猫
Cat cat = new Cat();
cat.setName(“豆豆”);
// 调用重写方法
cat.shout();
运行结果:
张三汪汪汪地叫~
豆豆喵喵喵地叫~
3.3 方法重写规则
关于方法重写,有以下规则:
-
重写方法的参数列表应该与原方法完全相同;
-
返回值类型应该和原方法的返回值类型一样或者是它在父类定义时的子类型;
-
重写方法访问级别限制不能比原方法高。例如:如果父类方法声明为公有的,那么子类中的重写方法不能是私有的或是保护的。具体限制级别参考访问修饰符;
-
只有被子类继承时,方法才能被重写;
-
方法定义为
final
,将不能被重写; -
一个方法被定义为 static,将使其不能被重写,但是可以重新声明;
-
一个方法不能被继承,那么也不能被重写;
-
和父类在一个包中的子类能够重写任何没有被声明为 private 和 final 的父类方法;
-
和父类不在同一个包中的子类只能重写 non-final 方法或被声明为 public 或 protected 的方法;
-
一个重写方法能够抛出任何运行时异常,不管被重写方法是否抛出异常。然而重写方法不应该抛出比被重写方法声明的更新更广泛的已检查异常。重写方法能够抛出比被重写方法更窄或更少的异常;
-
构造方法不能重写。
3.4 方法重写和方法重载的区别
Java 中的方法重写(Overriding
)是说子类重新定义了父类的方法。方法重写必须有相同的方法名,参数列表和返回类型。覆盖者访问修饰符的限定大于等于父类方法。
而方法重载(Overloading
)发生在同一个类里面两个或者是多个方法的方法名相同但是参数不同的情况。
4.1 作用
我们使用 private
和 public
两种访问修饰符实现了对类的封装。现在终于到了详细了解访问修饰符的时候了。
为了实现对类的封装和继承,Java 提供了访问控制机制。通过访问控制机制,类的设计者可以掩盖变量和方法来达到维护类自身状态的目的,而且还可以将另外一些需要暴露的变量和方法提供给别的类进行访问和修改。
4.2 种类
Java 一共提供了 4 种访问修饰符:
-
private:私有的,只允许在本类中访问;
-
protected:受保护的,允许在同一个类、同一个包以及不同包的子类中访问;
-
默认的:允许在同一个类,同一个包中访问;
-
public:公共的,可以再任何地方访问。
下表按照限定能力从大到小列出了访问修饰符在不同作用域的作用范围:
| 访问控制修饰符 | 同一个类 | 同一个包 | 不同包的子类 | 不同包的非子类 |
| :-- | :-- | :-- | :-- | :-- |
| private(私有的) | ✓ | ✕ | ✕ | ✕ |
| default(默认的) | ✓ | ✓ | ✕ | ✕ |
| protected(受保护的) | ✓ | ✓ | ✓ | ✕ |
| public(公共的) | ✓ | ✓ | ✓ | ✓ |
super
是用在子类中的,目的是访问直接父类的变量或方法。注意:
-
super 关键字只能调用父类的
public
以及protected
成员; -
super 关键字可以用在子类构造方法中调用父类构造方法;
-
super 关键字不能用于静态 (
static
) 方法中。
5.1 调用父类构造方法
父类的构造方法既不能被继承,也不能被重写。
可以使用 super
关键字,在子类构造方法中要调用父类的构造方法,语法为:
super(参数列表)
例如,父类 Pet
中存在构造方法:
package com.caq.oop.demo03;
public class Pet {
public Pet(String name) {
System.out.println(“名字为”+name);
}
}
子类 Cat
的构造方法中调用父类构造方法:
package com.caq.oop.demo03;
public class Cat extends Pet {
//子类 Cat
的构造方法中调用父类构造方法
public Cat(String name) {
super(name);
System.out.println(“调用父类的构造方法调用成功!”);
}
public static void main(String[] args) {
new Cat(“旺财”);
}
}
调用 Dog
有参构造方法,进行实例化:
new Dog(“花花”);
运行结果:
宠物实例被创建了,宠物名字为花花
小狗实例被创建了
5.2 调用父类属性
子类中可以引用父类的成员变量,语法为:
super.成员变量名
例如,在 Dog 类中调用父类的成员变量 birthday
:
class Pet {
protected String birthday;
}
class Dog extends Pet {
public Dog() {
System.out.println(“宠物生日:” + super.birthday);
}
}
5.3 调用父类方法
有时候我们不想完全重写父类方法,可以使用 super
关键字调用父类方法,调用父类方法的语法为:
super.方法名(参数列表)
例如,Cat 类调用父类 Pet 的 eat 方法:
class Pet {
public void eat() {
System.out.println(“宠物吃东西”);
}
}
class Cat extends Pet{
public void eat() {
// 在 eat 方法中调用父类 eat 方法
super.eat();
System.out.println(“小猫饭量很小”);
}
}
class Test {
public static void main(String[] args) {
Cat cat = new Cat();
cat.eat();
}
}
运行结果:
宠物吃东西
小猫饭量很小
5.4 super 与 this 的对比
this
关键字指向当前类对象的引用,它的使用场景为:
-
访问当前类的成员属性和成员方法;
-
访问当前类的构造方法;
-
不能在静态方法中使用。
super
关键字指向父类对象的引用,它的使用场景为:
-
访问父类的成员属性和成员方法;
-
访问父类的构造方法;
-
不能在静态方法中使用。
另外,需要注意的是,在构造方法调用时,super 和 this 关键字不能同时出现。
final
关键字可以作用于类、方法或变量,分别具有不同的含义。在使用时,必须将其放在变量类型或者方法返回之前,建议将其放在访问修饰符和 static
关键字之后,例如:
// 定义一个常量
public static final int MAX_NUM = 50;
6.1 final 作用于类
当 final
关键字用于类上面时,这个类不会被其他类继承:
final class FinalClass {
public String name;
}
// final类不能被继承,编译会报错
public class SubClass extends FinalClass {
}
编译执行,将会报错:
SubClass.java:1: 错误: 无法从最终FinalClass进行继承
public class SubClass extends FinalClass {
^
1 个错误
6.2 final 作用于方法
当父类中方法不希望被重写时,可以将该方法标记为 final
:
class SuperClass {
public final void finalMethod() {
System.out.println(“我是final方法”);
}
}
最后
按照上面的过程,4个月的时间刚刚好。当然Java的体系是很庞大的,还有很多更高级的技能需要掌握,但不要着急,这些完全可以放到以后工作中边用别学。
学习编程就是一个由混沌到有序的过程,所以你在学习过程中,如果一时碰到理解不了的知识点,大可不必沮丧,更不要气馁,这都是正常的不能再正常的事情了,不过是“人同此心,心同此理”的暂时而已。
“道路是曲折的,前途是光明的!”
}
// final类不能被继承,编译会报错
public class SubClass extends FinalClass {
}
编译执行,将会报错:
SubClass.java:1: 错误: 无法从最终FinalClass进行继承
public class SubClass extends FinalClass {
^
1 个错误
6.2 final 作用于方法
当父类中方法不希望被重写时,可以将该方法标记为 final
:
class SuperClass {
public final void finalMethod() {
System.out.println(“我是final方法”);
}
}
最后
按照上面的过程,4个月的时间刚刚好。当然Java的体系是很庞大的,还有很多更高级的技能需要掌握,但不要着急,这些完全可以放到以后工作中边用别学。
学习编程就是一个由混沌到有序的过程,所以你在学习过程中,如果一时碰到理解不了的知识点,大可不必沮丧,更不要气馁,这都是正常的不能再正常的事情了,不过是“人同此心,心同此理”的暂时而已。
“道路是曲折的,前途是光明的!”
[外链图片转存中…(img-d7Agj96Z-1714696929294)]
[外链图片转存中…(img-ooAswGf2-1714696929294)]