admin管理员组文章数量:1794759
Java学习【类与对象—继承与多态】
继承
当我们去定义一个student类和techer类时会发现里面有重复的属性,那如果我们相要写其他一些工作人员的类时,每一个类都要写这些重复的属性
这时当我们把这些属性抽取出来,定义在一个Person类中,每个类都写其中的特有元素
继承的关系是通过extends来实现的,也就是Student类继承了Person类的属性和方法 通过继承,提高了代码的复用性,子类可以在父类的基础上添加其他方法,让子类更强大
注意: Java中不支持多继承,但可以多层继承
继承中成员变量的访问
代码语言:javascript代码运行次数:0运行复制public class Fu {
String name = "Fu";
}
代码语言:javascript代码运行次数:0运行复制public class Zi extends Fu{
String name = "Zi";
public void ziShow(){
String name = "localZi";
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
public static void main(String[] args) {
Zi zi = new Zi();
zi.ziShow();
}
}
运行结果
可以看出,对于成员变量的访问遵循就近原则,通过关键字this访问本类成员变量,super访问当前类的父类的成员变量
继承中构造方法的访问
首先,我们要明白 父类中的构造方法是不会被子类继承的,可以通过super调用 子类中的所有构造方法默认先访问父类中的无参构造方法,再执行自己 原因: 子类在初始化的时候,有可能会用到父类中的数据,如果父类还没有初始化,那么子类就用不了父类的数据了,子类在初始化之前,一定要调用父类构造方法完成父类数据空间的初始化
代码语言:javascript代码运行次数:0运行复制public class Text {
public static void main(String[] args) {
Dog dog = new Dog();
}
}
class Animal{
public String name;
public Animal(){
System.out.println("父类构造方法");
}
}
class Dog extends Animal{
public Dog(){
System.out.println("子类构造方法");
}
}
根据打印结果可以看出,父类初始化,子类再初始化,也就是现有父再有子
子类调用父类构造方法: 子类构造方法第一句默认是super(),不写也存在,而且必须放在第一行 如果要调用父类的有参构造,就必须手动书写super进行调用
接下来看个例子理解一下:
所以最后输出的结果就是,先打印父类无参构造,再打印子类无参构造
那么子类怎么进行有参构造呢 这时就需要在子类的有参构造中通过super去调用父类的有参构造
还有一种传参方式,可以对比一下
这两种方法一个是在有参构造中调用父类的有参构造,一个是在无参构造中调用 super和this总结
相同点: 1.都是Java中的关键字 2.只能在类的非静态方法中使用,用来访问非静态成员方法和字段 3.在构造方法中调用时,必须是构造方法的第一条语句,并且不能同时存在 不同点: this是当前对象的引用,super相当于是子类对象从父类成员中继承下来部分成员的引用
继承和组合
继承的关系就是,一个事物是另一个大的事物的一种,例如猫是动物,而组合的关系就是一个事物是另一个事物的一部分,例如轮子是汽车的一部分,学生是学校的一部分这种 组合的实现
代码语言:javascript代码运行次数:0运行复制public class Car {
//汽车轮胎
private Tire[] tires;
//汽车引擎
private Engine engine;
//车载系统
private VehicleSystem vehicleSystem;
}
//轮胎类
class Tire{
//······
}
//发动机类
class Engine{
//······
}
//车载系统类
class VehicleSystem{
}
初始化执行顺序
先执行静态代码块,因为之前提到过,静态代码块是不依赖于对象的,接着执行父类的实例和构造,再执行子类的实例和构造
那如果再创建一个对象呢
代码语言:javascript代码运行次数:0运行复制Cat cat2 = new Cat("小白",5);
静态代码块只加载一次,然后随着对象的创建加载父类和子类
权限修饰符的介绍
private private很好理解,同一个包中的其它类就不能访问了,只能本类中才能访问 空着不写 空着不写也就是不加任何权限修饰符
代码语言:javascript代码运行次数:0运行复制String s1;
int a;
同一个包中的其他类能访问
也就是上面Textdemo中定义的变量,在Textdemo2中也能访问
protect
下面就是不同包中的子类的例子:
那么能用super去访问吗
很明显,编译器直接报错了,因为main方法也是static修饰的,不能用super public public字面意思就是公开的的,谁都能访问
final关键字
final表示最终的,不能被修改。
被final修饰的方法不能被重写:
修饰的类不能被继承: 例如Java中的String类就被final修饰,不能被继承,所以里面的所有方法不能被重写
修饰的变量叫做常量,只能被赋值一次:
多态
什么是多态呢,就是去完成某个行为,当不同的对象去完成时会产生不同的状态 多态实现的条件: 1.必须在继承体系下 2.子类必须对父类中的方法进行重写 3.通过父类的引用调用重写的方法 这些我们在之后慢慢理解
向上转型
向上转型就是创建一个子类对象,把它当成父类对象来使用,也就是父类引用了子类的对象 语法格式: 父类类型 对象名 = new 子类类型(),有以下三种方式可以达到父类引用子类对象的效果
直接赋值
代码语言:javascript代码运行次数:0运行复制Animal animal = new Dog("二哈",10);
方法传参
返回值
向上转型不能调用子类特有的方法
向下转型
向下转型和向上转型正好相反,也就是把父类的对象转化为子类的引用
代码语言:javascript代码运行次数:0运行复制public class Text {
public static void main(String[] args) {
Animal animal = new Dog("大黄",3);
// 向下转型
Dog dog = (Dog) animal;
dog.eat();
}
}
向下转型涉及到强制类型转换,所以存在风险,并不常用 还有一个注意点,强制转换并不是万能的
代码语言:javascript代码运行次数:0运行复制public static void main(String[] args) {
Animal animal = new Dog("大黄", 3);
// 向下转型
Dog dog = (Dog) animal;
dog.eat();
Animal animal1 = new Cat("Tom", 2);
Dog dog1 = (Dog) animal1; // 报错 ClassCastException
dog1.eat();
}
上面的代码会报错,这是因为转型前后的对象类型并不匹配 为了避免这种错误,通常会在进行向下转型之前使用instanceof关键字来检查对象是否是目标类的实例:
代码语言:javascript代码运行次数:0运行复制public static void main(String[] args) {
Animal animal = new Dog("大黄", 3);
// 向下转型,之前已经知道animal实际上是Dog类型
Dog dog = (Dog) animal;
dog.eat();
Animal animal1 = new Cat("Tom", 2);
// 检查animal1是否是Dog的实例
if (animal1 instanceof Dog) {
Dog dog1 = (Dog) animal1; // 如果animal1实际上是Dog,这行代码不会执行
dog1.eat();
} else {
System.out.println("animal1 不是一个 Dog 对象");
}
}
方法的重写
父类子类中的两个方法如果满足: 1.方法名相同 2.参数列表相同 3.返回值相同 就构成了方法的重写
重写的注意事项: 1.不能是静态方法,构造方法 2.不能被final,private修饰 3.子类重写父类的方法,子类的权限要大于等于父类 4.被重写的方法返回值类型可以不同,但必须是具有父子关系的
静态绑定:在编译时,根据用户所传入参数的类型就知道具体调用哪个方法,也就是重载的例子。
动态绑定: 当运行代码的时候,通过父类的引用,调用了父类和子类重写的那个方法,结果实际调用了子类的方法,叫做动态绑定,也就是在编译时,不能确定方法的行为,等到程序运行时才能够具体确定调用哪个类,
代码语言:javascript代码运行次数:0运行复制例如我们在测试类中通过向上转型的方式进行调用,虽然我们使用父类调用的方法,但运行结果是根据子类的方法运行的
public class Text {
public static void main(String[] args) {
Animal animal = new Dog("大黄",3);
animal.eat();
}
}
代码语言:javascript代码运行次数:0运行复制再看下面的代码,就对多态理解的更深了:
public class Text {
public static void main(String[] args) {
Dog dog = new Dog("大黄",3);
func(dog);
Cat cat = new Cat("小白",2);
func(cat);
}
public static void func(Animal animal){
animal.eat();
}
}
也就是不同的对象去调用同一个方法,有了不同的状态,这就叫做多态,但是编译还是按照父类animal的eat编译的,运行则是按照子类的eat方法运行
多态的优势: 方法中,可以使用父类型作为参数,可以接收所有的子类对象 弊端: 不能使用子类特有的方法
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2024-05-17,如有侵权请联系 cloudcommunity@tencent 删除继承java变量编译对象本文标签: Java学习类与对象继承与多态
版权声明:本文标题:Java学习【类与对象—继承与多态】 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1754847100a1707266.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论