Java继承
继承是面向对象编程的三大特性之一(封装,继承,多态),它允许子类继承父类的属性和方法,实现代码复用
1. 继承的基本概念
java
/**
* 父类(基类、超类)
*/
class Animal {
protected String name;
protected int age;
public Animal() {
System.out.println("Animal无参构造");
}
public Animal(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Animal有参构造");
}
public void eat() {
System.out.println(name + "正在吃东西");
}
public void sleep() {
System.out.println(name + "正在睡觉");
}
public void display() {
System.out.println("名字: " + name + ", 年龄: " + age);
}
}
/**
* 子类(派生类)- 单继承
*/
class Dog extends Animal {
private String breed; // 品种
public Dog() {
super(); // 调用父类无参构造(默认存在)
System.out.println("Dog无参构造");
}
public Dog(String name, int age, String breed) {
super(name, age); // 调用父类有参构造
this.breed = breed;
System.out.println("Dog有参构造");
}
// 子类特有的方法
public void bark() {
System.out.println(name + "正在汪汪叫");
}
// 重写父类方法
@Override
public void eat() {
System.out.println(name + "正在吃狗粮");
}
}
public class InheritanceBasic {
public static void main(String[] args) {
// 创建子类对象
Dog dog = new Dog("旺财", 3, "金毛");
dog.eat(); // 调用重写的方法
dog.sleep(); // 调用继承的方法
dog.bark(); // 调用子类特有方法
dog.display(); // 调用继承的方法
}
}
2. 继承的特性
java
/**
* 演示继承的各种特性
*/
class Parent {
// 1. 访问修饰符对继承的影响
public String publicField = "public字段";
protected String protectedField = "protected字段";
String defaultField = "default字段";
private String privateField = "private字段";
public void publicMethod() {
System.out.println("public方法");
}
protected void protectedMethod() {
System.out.println("protected方法");
}
void defaultMethod() {
System.out.println("default方法");
}
private void privateMethod() {
System.out.println("private方法");
}
// 2. 静态方法
public static void staticMethod() {
System.out.println("父类静态方法");
}
// 3. final方法(不能被重写)
public final void finalMethod() {
System.out.println("final方法,不能被重写");
}
// 4. 普通方法示例
public void show() {
System.out.println("父类show方法");
}
}
class Child extends Parent {
// 可以访问父类的public、protected、default成员
public void testAccess() {
System.out.println(publicField); // ✅ 可以访问
System.out.println(protectedField); // ✅ 可以访问
System.out.println(defaultField); // ✅ 可以访问(同包)
// System.out.println(privateField); // ❌ 不能访问
}
// 重写父类方法
@Override
public void show() {
System.out.println("子类重写的show方法");
}
// 静态方法不能重写,只能隐藏
public static void staticMethod() {
System.out.println("子类静态方法(隐藏父类方法)");
}
// ❌ 不能重写final方法
// public void finalMethod() { } // 编译错误
}
public class InheritanceFeatures {
public static void main(String[] args) {
Child child = new Child();
child.testAccess();
child.show(); // 调用子类重写的方法
child.publicMethod(); // 继承的方法
child.protectedMethod(); // 继承的方法
// 静态方法调用(推荐使用类名调用)
Parent.staticMethod();
Child.staticMethod();
}
}
3. 多层继承
java
/**
* 多层继承:GrandFather -> Father -> Son
*/
class GrandFather {
protected String familyName = "王";
protected String bloodType = "A型";
public GrandFather() {
System.out.println("GrandFather构造");
}
public void work() {
System.out.println("祖父在工作");
}
public void showGene() {
System.out.println("家族姓氏: " + familyName + ", 血型: " + bloodType);
}
}
class Father extends GrandFather {
protected String car = "大众";
public Father() {
System.out.println("Father构造");
}
@Override
public void work() {
System.out.println("父亲在工作");
}
public void drive() {
System.out.println("父亲开车: " + car);
}
}
class Son extends Father {
private String hobby = "编程";
public Son() {
System.out.println("Son构造");
}
@Override
public void work() {
System.out.println("儿子在工作");
}
public void code() {
System.out.println("儿子爱好: " + hobby);
}
public void showAll() {
System.out.println("家族姓氏: " + familyName); // 来自祖父
System.out.println("血型: " + bloodType); // 来自祖父
System.out.println("汽车: " + car); // 来自父亲
System.out.println("爱好: " + hobby); // 自己的
}
}
public class MultiLevelInheritance {
public static void main(String[] args) {
Son son = new Son();
System.out.println("=== 调用各层方法 ===");
son.work(); // 儿子重写的方法
son.drive(); // 父亲的方法
son.code(); // 自己的方法
son.showGene(); // 祖父的方法
son.showAll(); // 综合显示
System.out.println("\n=== 构造顺序 ===");
// 输出顺序:GrandFather构造 -> Father构造 -> Son构造
// 构造时先调用父类构造器
}
}
4. super关键字
java
/**
* super关键字的用法
*/
class Person {
protected String name;
protected int age;
public Person() {
this("未知", 0);
System.out.println("Person无参构造");
}
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Person有参构造: " + name + ", " + age);
}
public void display() {
System.out.println("Person: " + name + ", " + age);
}
public void sayHello() {
System.out.println("Person打招呼");
}
}
class Student extends Person {
private String school;
private int grade;
public Student() {
// super(); // 隐含调用父类无参构造
this("未知", 0, "未知学校", 0);
System.out.println("Student无参构造");
}
public Student(String name, int age, String school, int grade) {
super(name, age); // 调用父类有参构造,必须在第一行
this.school = school;
this.grade = grade;
System.out.println("Student有参构造");
}
@Override
public void display() {
super.display(); // 调用父类的display方法
System.out.println("Student: " + school + ", " + grade + "年级");
}
@Override
public void sayHello() {
super.sayHello(); // 调用父类方法
System.out.println("Student打招呼: 我是" + name);
}
public void testSuper() {
// super可以访问父类的成员
System.out.println(super.name); // 访问父类字段
super.display(); // 调用父类方法
// super() // ❌ 只能在构造方法的第一行使用
}
}
public class SuperKeyword {
public static void main(String[] args) {
System.out.println("=== 创建Student对象 ===");
Student stu = new Student("张三", 18, "清华大学", 1);
System.out.println("\n=== 调用display ===");
stu.display();
System.out.println("\n=== 调用sayHello ===");
stu.sayHello();
}
}
Java重写
重写是子类重新定义父类的方法,实现运行时多态
1. 重写的基本规则
java
class ParentClass {
// 1. 方法签名必须相同(方法名和参数列表)
public void method1() {
System.out.println("Parent method1");
}
// 2. 返回值类型:可以是父类返回类型的子类型(协变返回类型)
public Object method2() {
System.out.println("Parent method2");
return new Object();
}
// 3. 访问修饰符:不能比父类更严格
protected void method3() {
System.out.println("Parent method3");
}
// 4. 异常声明:不能抛出比父类更宽泛的异常
public void method4() throws Exception {
System.out.println("Parent method4");
}
}
class ChildClass extends ParentClass {
@Override
public void method1() {
System.out.println("Child method1");
}
@Override
public String method2() { // String是Object的子类,协变返回类型
System.out.println("Child method2");
return "String返回值";
}
@Override
public void method3() { // 可以扩大访问权限(public > protected)
System.out.println("Child method3");
}
@Override
public void method4() throws IOException { // IOException是Exception的子类
System.out.println("Child method4");
}
}
public class OverrideRules {
public static void main(String[] args) {
ParentClass pc = new ChildClass();
pc.method1(); // 调用子类方法
pc.method2(); // 调用子类方法
pc.method3(); // 调用子类方法
}
}
2. @Override注解
java
class Base {
public void show() {
System.out.println("Base show");
}
}
class Derived extends Base {
@Override // 可选但推荐,可以帮助编译器检查
public void show() {
System.out.println("Derived show");
}
// @Override // ❌ 编译错误,这不是重写
public void display() {
System.out.println("Derived display");
}
}
3.动态绑定(运行时多态)
java
class Vehicle {
public void start() {
System.out.println("交通工具启动");
}
}
class Car extends Vehicle {
@Override
public void start() {
System.out.println("汽车启动:点火、踩离合、挂挡");
}
}
class Bicycle extends Vehicle {
@Override
public void start() {
System.out.println("自行车启动:踩脚踏板");
}
}
class Motorcycle extends Vehicle {
@Override
public void start() {
System.out.println("摩托车启动:打火、加油门");
}
}
public class DynamicBinding {
public static void main(String[] args) {
Vehicle v1 = new Car();
Vehicle v2 = new Bicycle();
Vehicle v3 = new Motorcycle();
v1.start(); // 运行时调用Car的start
v2.start(); // 运行时调用Bicycle的start
v3.start(); // 运行时调用Motorcycle的start
// 多态数组
Vehicle[] vehicles = {new Car(), new Bicycle(), new Motorcycle()};
for (Vehicle v : vehicles) {
v.start(); // 动态绑定
}
}
}
Java重载
1. 重载的基本规则
重载是同一个类中定义多个同名但参数列表不同的方法;
java
/**
* 方法重载示例
*/
class Calculator {
// 1. 参数个数不同
public int add(int a, int b) {
System.out.println("调用add(int, int)");
return a + b;
}
public int add(int a, int b, int c) {
System.out.println("调用add(int, int, int)");
return a + b + c;
}
// 2. 参数类型不同
public double add(double a, double b) {
System.out.println("调用add(double, double)");
return a + b;
}
// 3. 参数顺序不同
public String add(String str, int num) {
System.out.println("调用add(String, int)");
return str + num;
}
public String add(int num, String str) {
System.out.println("调用add(int, String)");
return num + str;
}
// ❌ 以下不是重载(只有返回值类型不同)
// public int add(int a, int b) { return a + b; }
// public long add(int a, int b) { return (long)a + b; }
}
public class OverloadDemo {
public static void main(String[] args) {
Calculator calc = new Calculator();
System.out.println(calc.add(5, 10)); // add(int, int)
System.out.println(calc.add(5, 10, 15)); // add(int, int, int)
System.out.println(calc.add(3.14, 2.86)); // add(double, double)
System.out.println(calc.add("数字: ", 100)); // add(String, int)
System.out.println(calc.add(200, " 是数字")); // add(int, String)
}
}
2. 重载的常见应用
java
/**
* 构造函数重载
*/
class StudentInfo {
private String name;
private int age;
private String major;
private double score;
// 构造方法重载
public StudentInfo() {
this("未知", 0, "未定", 0.0);
}
public StudentInfo(String name) {
this(name, 0, "未定", 0.0);
}
public StudentInfo(String name, int age) {
this(name, age, "未定", 0.0);
}
public StudentInfo(String name, int age, String major) {
this(name, age, major, 0.0);
}
public StudentInfo(String name, int age, String major, double score) {
this.name = name;
this.age = age;
this.major = major;
this.score = score;
}
public void display() {
System.out.printf("姓名: %s, 年龄: %d, 专业: %s, 分数: %.1f\n",
name, age, major, score);
}
}
/**
* 方法重载的实际应用
*/
class StringUtil {
// 重载的反转方法
public String reverse(String str) {
return new StringBuilder(str).reverse().toString();
}
public String reverse(String str, int start, int end) {
char[] chars = str.toCharArray();
for (int i = start, j = end; i < j; i++, j--) {
char temp = chars[i];
chars[i] = chars[j];
chars[j] = temp;
}
return new String(chars);
}
// 重载的查找方法
public int find(String str, char target) {
return str.indexOf(target);
}
public int find(String str, String target) {
return str.indexOf(target);
}
public int find(String str, char target, int fromIndex) {
return str.indexOf(target, fromIndex);
}
// 重载的格式化方法
public String format(String template, String... args) {
String result = template;
for (int i = 0; i < args.length; i++) {
result = result.replace("{" + i + "}", args[i]);
}
return result;
}
public String format(String template, Object... args) {
return String.format(template, args);
}
}
public class OverloadApplications {
public static void main(String[] args) {
// 构造方法重载
StudentInfo s1 = new StudentInfo();
StudentInfo s2 = new StudentInfo("张三");
StudentInfo s3 = new StudentInfo("李四", 20);
StudentInfo s4 = new StudentInfo("王五", 21, "计算机");
StudentInfo s5 = new StudentInfo("赵六", 22, "数学", 95.5);
s1.display();
s2.display();
s3.display();
s4.display();
s5.display();
// 方法重载
StringUtil util = new StringUtil();
System.out.println(util.reverse("Hello"));
System.out.println(util.reverse("Hello World", 0, 4));
System.out.println(util.find("Hello World", 'o'));
System.out.println(util.find("Hello World", "World"));
System.out.println(util.format("Hello {0}, welcome to {1}", "张三", "Java"));
}
}
3. 重载的自动类型转换
java
class TypeConversion {
public void method(int a) {
System.out.println("int: " + a);
}
public void method(long a) {
System.out.println("long: " + a);
}
public void method(double a) {
System.out.println("double: " + a);
}
public void method(Integer a) {
System.out.println("Integer: " + a);
}
public void method(int... a) {
System.out.println("可变参数: " + a.length);
}
}
/**
* 重载方法的匹配顺序
* 1. 精确匹配
* 2. 自动类型转换(向上转型)
* 3. 装箱/拆箱
* 4. 可变参数
*/
public class OverloadPriority {
public static void main(String[] args) {
TypeConversion tc = new TypeConversion();
tc.method(10); // 精确匹配 int
tc.method((byte)10); // 自动类型转换 byte -> int
tc.method((short)10); // 自动类型转换 short -> int
tc.method(10L); // 精确匹配 long(不是int转long)
tc.method(10.0f); // float -> double
tc.method(10.0); // 精确匹配 double
tc.method(10); // 装箱成Integer(如果没有int匹配)
tc.method(10, 20); // 可变参数
}
}
四、重写 vs 重载对比
java
/**
* 重写 vs 重载对比示例
*/
class Parent {
// 父类方法
public void method(int a) {
System.out.println("Parent method(int): " + a);
}
public void method(String s) {
System.out.println("Parent method(String): " + s);
}
// 将被重写的方法
public void show() {
System.out.println("Parent show");
}
// 将被重写的方法(有返回值)
public Object getValue() {
return new Object();
}
}
class Child extends Parent {
// 重载:在子类中增加新方法
public void method(String s, int a) {
System.out.println("Child method(String, int): " + s + ", " + a);
}
// 重写:重新定义父类方法
@Override
public void show() {
System.out.println("Child show");
}
// 重写:协变返回类型
@Override
public String getValue() {
return "Child value";
}
}
public class OverrideVsOverload {
public static void main(String[] args) {
Parent p = new Parent();
Child c = new Child();
Parent pc = new Child(); // 多态
System.out.println("=== 重载 ===");
p.method(10); // 调用父类method(int)
p.method("Hello"); // 调用父类method(String)
c.method(20); // 继承的method(int)
c.method("World"); // 继承的method(String)
c.method("Hi", 30); // 子类新增的重载方法
System.out.println("\n=== 重写 ===");
p.show(); // 调用父类show
c.show(); // 调用子类show
pc.show(); // 多态调用子类show
System.out.println("\n=== 协变返回类型 ===");
System.out.println(p.getValue().getClass()); // Object
System.out.println(c.getValue().getClass()); // String
System.out.println(pc.getValue().getClass()); // String
}
}