继承和多态性经常一起使用。通过继承,子类可以继承父类的属性和方法,并且可以重写这些方法来实现自己的功能。而通过多态性,可以在父类中定义一个方法,让所有的子类都去实现这个方法,从而实现不同子类的不同行为。这样可以让代码更加灵活、可扩展和易维护。
继承是一种面向对象编程的概念,它允许一个类继承另一个类的属性和方法。被继承的类称为父类或基类,继承的类称为子类或派生类。子类可以继承父类中所有可见的属性和方法,包括公共、受保护和默认级别的成员变量和方法,但不包括私有成员变量和方法。
例:创建子类对象,观察构造方法执行顺序
例:在电话类基础上衍生出手机类
Java虽然不允许同时继承两个父类,但不代表没有多继承的关系,可以通过类似“祖父>父>儿子>孙子”的方式实现多代继承。
例:绝大多数动物有眼睛,鼻子和嘴,犬类继承动物类,所以犬类也有眼睛,鼻子和嘴,哈士奇是犬类的一个品种,犬类有的特征哈士奇都有,但哈士奇的眼睛鼻子和嘴并不是从犬类继承的,而是从动物类继承的。
class Animal { //父类:动物类
Eyes eyes;
Nose nose;
Mouth mouth;
}
class Dog extends Animal{} //子类:犬类
class Husky extends Dog{} //子类:哈士奇类
Java中所有的类都是直接或间接继承自Object类。Object类是Java中的基类,它提供了一些常用的方法和属性,可以被其他所有的类继承和使用。
getClass()方法:用于获取对象的类对象。可以使用getClass()方法来获取对象的类名、访问类的属性和方法等信息。
语法如下:
getClass().getName();
getClass()方法与toString()方法可以联合使用 。
toString()方法:用于将对象转换为字符串表示。默认情况下,toString()方法返回对象的类名和内存地址,但可以被子类重写来实现自定义的字符串表示。
例:让学生自我介绍
equals()方法:用于比较两个对象是否相等。默认情况下,equals()方法比较的是两个对象的引用是否相等,但可以被子类重写来实现自定义的相等比较。
例:根据身份证号判断是否为同一人
Java中,对象类型的转换包括向上转型和向下转型两种类型。
向上转型是指将子类对象转换成父类对象的过程。这种转换是自动完成的,无需任何显式的类型转换操作。由于子类继承了父类的属性和方法,因此可以将子类对象看作是父类对象的一种特殊形式,从而可以将子类对象赋值给父类对象。
例,假设有一个Animal类和一个Cat类,Cat类是Animal类的子类。可以使用如下的代码进行向上转型:
javaCopy code
Animal animal = new Cat();
在这个例子中,创建了一个Cat对象,并将其赋值给Animal类型的引用变量animal。由于Cat类是Animal类的子类,因此可以将Cat对象向上转型成Animal对象。
向下转型是指将父类对象转换成子类对象的过程。这种转换需要显式的类型转换操作,并且需要确保父类对象实际上是子类对象的实例。如果转换不正确,则会引发ClassCastException异常。
例,假设有一个Animal类和一个Cat类,可以使用如下的代码进行向下转型:
javaCopy codeAnimal animal = new Cat();
Cat cat = (Cat)animal;
在这个例子中,首先将一个Cat对象向上转型成Animal对象,并将其赋值给一个Animal类型的引用变量animal。然后,将animal对象向下转型成Cat对象,并将其赋值给一个Cat类型的引用变量cat。由于animal对象实际上是Cat对象的实例,因此可以将其向下转型成Cat对象。
需要注意,在进行向下转型时需要确保父类对象实际上是子类对象的实例。可以使用instanceof运算符来检查对象的类型,从而避免ClassCastException异常的发生。
instanceof关键字是用于检查对象的类型。它的语法格式为:
javaCopy code
对象 instanceof 类名
其中,对象是要检查的对象,类名是要检查的类名或接口名。如果对象是该类或接口的一个实例,则返回true;否则返回false。
instanceof可以用来检查对象的类型,从而避免进行不正确的类型转换。例如,假设有一个Animal类和一个Cat类,可以使用如下的代码进行类型检查:
javaCopy codeAnimal animal = new Cat();
if (animal instanceof Cat) {
Cat cat = (Cat)animal;
// 执行 Cat 类型的操作
} else {
// 处理 Animal 类型的情况
}
在这个例子中,首先将一个Cat对象向上转型成Animal对象,并将其赋值给一个Animal类型的引用变量animal。然后,使用instanceof检查animal对象是否是Cat类型的实例,如果是,则将其向下转型成Cat对象,并执行Cat类型的操作;否则,处理Animal类型的情况。
需要注意,instanceof只能用来检查对象的类型,不能用来检查基本类型。例如,不能使用instanceof来检查int类型的变量。此外,instanceof也不能用来检查对象的泛型类型。
方法的重载(Overloading)是指在同一个类中可以定义多个方法名相同但参数类型、个数或顺序不同的方法。重载方法可以让程序代码更加简洁、清晰,并且可以根据不同的参数类型、个数和顺序进行不同的处理。
方法的重载需要满足以下两个条件:
1.方法名相同
2.参数列表不同,包括参数类型、个数或顺序不同
注意:返回值类型不是方法的重载条件。
例,下面就是一个计算两个整数之和的重载方法:
public int sum(int a, int b) {
return a + b;
}
public int sum(int a, int b, int c) {
return a + b + c;
}
public int sum(double a, double b) {
return (int)(a + b);
}
上面的三个方法都是sum,但是它们的参数列表不同,所以它们是不同的方法。我们可以根据参数的不同类型、个数或顺序调用不同的方法,实现相应的功能。例如:
int result1 = sum(1, 2);
int result2 = sum(1, 2, 3);
int result3 = sum(1.0, 2.0);
通过方法的重载,我们可以使用相同的方法名来完成不同的功能,这样可以提高代码的重用性和可读性。
例:编写不同形式的加法运算方法
在谈到参数个数可以确定两个方法是否具有重载关系时,会想到定义不定长参数方法。不定长方法语法如下:
返回值 方法名(参数数据类型…参数名称)
例:使用不定长参数重载加法运算方法
在上述实例中,在参数列表中使用“…”形式定义不定长参数,其实这个不定长参数a就是一个数组,编译器会将“int…a”这种形式看成“int[] a”,所以在add()方法体做累加操作时使用到了for循环语句,在循环中是根据数组a的长度作为循环条件的,最后将累加结果返回。
final 是 Java 中的一个关键字,可以用来修饰类、方法和变量。使用 final 修饰的类不能被继承,使用 final 修饰的方法不能被子类重写,使用 final 修饰的变量不能被修改。
final关键字可以用于修饰变量,被final修饰的变量称为final变量。final变量是指在声明时必须被初始化,并且在程序执行过程中其值不可更改的变量。
final变量的值一旦被赋值就不能再改变,这使得程序具有更好的安全性和稳定性。在Java编程中,final变量通常用来表示常量或配置参数。
例:定义不允许的常量π
final关键字可以用于修饰类、方法和变量。当final用于修饰方法时,该方法就称为final方法。
final方法是指在类中声明的方法,在子类中不能被重写或覆盖。这意味着,当一个方法被声明为final时,它的实现在父类中是最终的,子类不能对其进行修改。
下面是一个示例代码,演示了如何在Java中使用final方法:
csharpCopy codepublic class Animal {
public final void move() {
System.out.println("Animal is moving...");
}
}
public class Cat extends Animal {
// 重写move方法会引发编译时错误
}
在这个例子中,Animal类定义了一个名为move的final方法。由于move方法被声明为final,它不能在子类中被重写或覆盖。因此,在Cat类中重写move方法会引发编译时错误。
final方法的优点是能够防止子类修改父类中的行为。如果一个方法被声明为final,那么它的实现在所有子类中都是不变的。这可以确保程序的稳定性和可靠性,同时也可以提高程序的执行效率。
在Java中,final关键字可以用于修饰类,被final修饰的类称为final类。final类是指不能被继承的类,即其子类不能被创建。
当一个类被声明为final时,它的实现在程序执行过程中是最终的,不能被修改或扩展。这意味着,final类的行为在所有的子类中都是不变的,可以确保程序的稳定性和安全性。
下面是一个示例代码,演示了如何在Java中使用final类:
arduinoCopy codepublic final class MathUtils {
public static int add(int a, int b) {
return a + b;
}
public static int multiply(int a, int b) {
return a * b;
}
}
在这个例子中,定义了一个名为MathUtils的final类。由于MathUtils类被声明为final,它不能被继承,即其子类不能被创建。MathUtils类中包含了两个静态方法add和multiply,这些方法可以被其他类直接调用,无需创建MathUtils类的实例。
final类的优点是可以确保程序的稳定性和安全性,同时也可以提高程序的执行效率。因为final类不能被继承,所以它的实现在所有的子类中都是不变的,这可以防止子类修改或扩展final类的行为。
在Java中,多态是指同一种行为或操作作用于不同的对象时,可以产生不同的结果。具体来说,多态可以通过继承和接口实现。
继承多态:子类可以重写父类的方法,当父类的引用指向子类的对象时,调用该方法时会调用子类中的方法实现。这种行为称为动态绑定或运行时绑定。例如:
csharpCopy codepublic class Animal {
public void move() {
System.out.println("Animal is moving...");
}
}
public class Cat extends Animal {
public void move() {
System.out.println("Cat is moving...");
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Cat();
animal.move(); // 输出:Cat is moving...
}
}
在这个例子中,定义了一个名为Animal的父类和一个名为Cat的子类,Cat类重写了Animal类中的move方法。在主方法中,创建了一个Animal类的引用,指向Cat类的对象。当调用animal.move()方法时,输出的结果为"Cat is moving…",这说明方法的实现是动态绑定的,即运行时决定调用哪个方法。
接口多态:当一个类实现了接口后,可以通过接口类型的引用指向该类的对象。这种行为称为接口多态。例如:
csharpCopy codepublic interface Shape {
void draw();
}
public class Rectangle implements Shape {
public void draw() {
System.out.println("Drawing a rectangle...");
}
}
public class Circle implements Shape {
public void draw() {
System.out.println("Drawing a circle...");
}
}
public class Main {
public static void main(String[] args) {
Shape shape1 = new Rectangle();
Shape shape2 = new Circle();
shape1.draw(); // 输出:Drawing a rectangle...
shape2.draw(); // 输出:Drawing a circle...
}
}
在这个例子中,定义了一个名为Shape的接口和两个实现了Shape接口的类Rectangle和Circle。在主方法中,创建了两个Shape类型的引用,分别指向Rectangle类和Circle类的对象。当调用shape1.draw()方法和shape2.draw()方法时,分别输出"Drawing a rectangle…“和"Drawing a circle…”,这说明方法的实现也是动态绑定的。
例:万能的绘图方法
使用abstract关键字定义的类称为抽象类,而使用这个关键字定义的方法称为抽象方法。抽象方法没有方法体,这个方法本身没有任何意义,除非它被重写,而承载这个抽象方法的抽象类必须被继承,实际上抽象类除了被继承没有任何意义。定义抽象类的语法如下:
public abstract class Parent{ abstract void testAbstrac(); //定义抽象方法
抽象类被继承后需要实现其中所有的抽象方法,也就是保证以相同的方法名称,参数列表和返回值类型创建出的非抽象方法,当然也可以是抽象方法。
抽象方法
修饰符 abstract 返回参数 方法名(传入参数);
抽象类 有抽象方法的类一定是抽象类
修饰符 abstract class 类名{
}
接口是抽象类的延伸,可以将它看作为是纯粹的抽象类,接口中的所有方法都没有方法体。
接口通过关键字“interface”来定义,接口中的方法默认是public abstract类型的,常量是public static final类型的。接口可以被类实现(implements),表示类遵循了该接口的规范,同时必须实现该接口中定义的所有抽象方法。语法如下:
public interface Paintable{
void draw(); //定义接口方法可省略public abstract关键字
}
一个类可以实现多个接口,但只能继承一个父类。这使得接口成为了Java中实现多继承的一种方式。通过实现多个接口,一个类可以拥有多种类型的行为特征。
接口也可以继承(extends)其他接口,这使得接口可以通过继承机制扩展接口的行为特征。当一个接口继承了另一个接口时,它将自动包含另一个接口中的所有常量和方法定义。
总之,接口提供了一种机制,用于定义类的一组操作行为,并将这些行为规范化,以便在实现类中实现具体的操作行为。
例:将绘图方法设为接口方法