目录
1.Java中子类能够继承父类的private属性或方法吗?
继承
概述
是面向对象三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义、追加属性和方法。
特点
格式:
public class 子类名 extends 父类名 ()
public class Zi extends Fu()
//Zi,子类,也被称为派生类
//Fu,父类,也被称为超类,基类
好处:
① 提高了代码的复用性 ----将子类中相同的成员放到父类中
② 提高了代码的维护性 ----修改方法的时候只需要修改父类方法那一处
弊端:
① 让类与类产生了关系,增强了耦合性----当父类发生变化时子类也不得不跟着变化,削弱了
子类的独立性。
什么时候使用继承:
继承体现的关系----is a
如果a是b的一种或者b是a的一种就说明他们存在继承关系
举例:苹果和水果,猫和动物,学生和人......他们都有共同的属性
反例:猫和狗,苹果和菠萝....这些类都是继承自同一个父类的。
super关键字
用法和this关键字类似。
super代表父类存储空间的标识,可以理解为父类对象引用。用法同下
例:super.成员变量 访问父类成员变量
this关键字用法
this代表本类对象的引用
this.成员变量 ---访问本类成员变量
this(参数) ---访问本类构造方法 (参数参考构造方法)
this.成员方法(参数) ---访问本类成员方法 (参数参考成员方法的参数)
☆构造方法的访问特点
① 子类中所有的构造方法都会访问父类中无参的构造方法
原因;因为子类会继承父类中的数据,可能还会使用父类的数据,因此在子类初始化之前要对父类先初始化。
② 如果父类没有设置无参构造方法,子类的构造方法中可以super(参数)来引用父类带参构造方法。推荐的是在父类中给出无参构造方法。
案例:
class Super {
int i = 0;
public Super(String s) {
i = 1;
}
}
class Demo extends Super {
public Demo(String s) {
i = 2;
}
public static void main(String[] args) {
Demo d = new Demo("yes");
System.out.println(d.i);
}
}
这段代码Super类没有设置默认构造方法,因此在Demo类设置构造方法时报错了,这个时候可以在Super类中添加默认构造方法,或者在Demo类的有参构造方法,即i=2上一行添加super(s)
方法重写
概念
子类中出现了和父类中一模一样的方法声明。
应用
当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。这样,既沿袭了父类的功能,又定义了子类特有的内容。
例:手机类和新手机类。新手机类继承手机类,它需要实现父类所有的功能,并且还有自己特有的功能例如智能连接家居。那就可以在子类中重写父类的方法,方法体内的第一步是super.() 这样就可以将父类的成员方法内容实现,下面再加上新功能连接家居就可以在父类的基础上增加子类的功能了!
注意事项
① 父类中的私有方法不能被子类重写
② 子类重写方法时 方法的访问权限要 不低于父类的方法访问权限
访问权限 : public>protected>默认 >private
重写与重载的区别
重载和重写都需要同样的方法名,重载是在同一个类中,重写是在子类,对父类的重写。重载需要不同的参数类型或者数量 与返回值无关,重写则要求参数与返回值等都要相同
继承的注意事项
① 类不能同时继承多个类
② 支持多层继承
继承案例
1.Vehicle.java
/* 编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数wheels和车重weight。
小车类Car是Vehicle的子类,其中包含的属性有载人数loader。卡车类Truck是Car类的子类,其中包含的属性有载重量payload。
(1)每个类都有构造方法进行属性初始化
(2)每个类都输出相关数据的toString方法
(3)使用Test类中的main方法定义各类初始化数据后台打印相关数据*/
public class Vehicle {
private int wheels;
private double weight;
//两个构造方法
public Vehicle() {
}
public Vehicle(int wheels, double weight) {
this.wheels = wheels;
this.weight = weight;
}
//每个private变量的get/set方法
public int getWheels() {
return wheels;
}
public void setWheels(int wheels) {
this.wheels = wheels;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
//重写的toString方法
@Override
public String toString() {
return "Vehicle{" +
"wheels=" + wheels +
", weight=" + weight +
'}';
}
}
2.Car.java
public class Car extends Vehicle{
/* 编写一个Java应用程序,设计一个汽车类Vehicle,包含的属性有车轮个数wheels和车重weight。
小车类Car是Vehicle的子类,其中包含的属性有载人数loader。卡车类Truck是Car类的子类,其中包含的属性有载重量payload。
(1)每个类都有构造方法进行属性初识化
(2)每个类都输出相关数据的toString方法
(3)使用Test类中的main方法定义各类初始化数据后台打印相关数据*/
//成员变量
private int loader;
//构造方法
public Car(int loader) {
this.loader = loader;
}
public Car(int wheels, double weight, int loader) {
super(wheels, weight);
this.loader = loader;
}
//get/set
public int getLoader() {
return loader;
}
public void setLoader(int loader) {
this.loader = loader;
}
//重写toString 由于Wheels定义的是私有属性,我们无法直接访问,因此需要用get方法获取
@Override
public String toString() {
return "Car{" +
"wheels=" + getWheels() +
", weight=" + getWeight() +
",loader=" + loader +
'}';
}
}
3.Truck.java
//技巧同上
public class Truck extends Vehicle{
private double payload;
public Truck(double payload) {
this.payload = payload;
}
public Truck(int wheels, double weight, double payload) {
super(wheels, weight);
this.payload = payload;
}
public double getPayload() {
return payload;
}
public void setPayload(double payload) {
this.payload = payload;
}
@Override
public String toString() {
return "Truck{" + "wheels=" + getWheels() +
", weight=" + getWeight() +
",payload=" + payload +
'}';
}
}
进阶知识点
1.Java中子类能够继承父类的private属性或方法吗?
答案:可以的
父类的私有属性和方法子类是无法直接访问的,并不能代表父类的私有属性不能被继承。
子类对象确实拥有父类对象中所有的属性和方法,但是父类对象中的私有属性和方法,子类是无法访问到的,只是拥有,但不能使用。就像有些东西你可能拥有,但是你并不能使用。要想访问就需要提供set/get方法了!
结论:可以继承,只是无法访问到而已。
2.Object类
Object 类位于 java.lang 包中,是所有 Java 类的祖先,Java 中的每个类都由它扩展而来。
在Java中,只有基本类型不是对象,例如数值、字符和布尔型的值都不是对象,所有的数组类型,不管是对象数组还是基本类型数组都是继承自 Object 类。
Object 类定义了一些有用的方法,由于是根类,这些方法在其他类中都存在,一般是进行了重载或覆盖,实现了各自的具体功能。
3.equals()方法
Object 类中的 equals() 方法用来检测一个对象是否等价于另外一个对象,语法为:
public boolean equals(Object obj)
2.hashCode() 方法
3.toString() 方法
返回值是 String 类型,用于描述当前对象的有关信息。
多态
概述:
是一个对象在不同时刻表现出来的不同形态。
举例:猫
可以说
①猫是猫 猫 cat = new 猫();
②猫是动物 动物 animal=new 猫();
猫在不同时刻表现出来的不同形态,就是多态。
前提和体现
① 有继承/实现关系
② 有方法重写
③ 有父类/接口引用指向(子/实现)类对象
成员访问特点
☆ 通过多态的形式访问成员变量,编译和运行都看左边的类;访问成员方法,编译看左边,运行看右边,简单理解就是运行重写之后的方法。
原因:成员方法有重写,成员变量没有。
好处
好处:提高了程序的扩展性。
△理解:定义方法的时候,使用父类型作为参数,将来在使用的时候,使用具体的子类型参与操作。
多态中的转型
向上转型:
父类引用 指向子类对象
例:animal a =new cat()
注意:a不能使用cat的特有功能。
向下转型:
子类型 对象名=(子类型)父类引用
例: cat c=(cat) a
注意:
① 向下转型可以理解为强制类型转换。
② 两个继承同样父类的子类不能转型。
案例
1
public class Animal {
public void eat() {
System.out.println("动物吃~~");
}
}
public class bird extends Animal{ //继承关系
public void eat() { //重写方法
System.out.println("鸟吃虫子");
}
public void fly() { //子类特有方法
System.out.println("鸟儿正在飞");
}
}
public class Test {
public static void main(String[] args) {
Animal one = new bird(); //1 //向上转型
one.eat(); //2 //调用重写的方法
one.fly(); //3 //调用子类特有方法
}
}
案例中可以看到
① 多态的前提:继承关系--bird extends Animal
② 方法的重写:eat()
③ 向上转型:‘’1‘’处 ---不能调用子类特有方法
所以:
“2”处可以正常运行
“3”处会报错,应删除。或者使用向下转型再调用,这交给读者思考。
2
public class Father {
public void show() {
System.out.println("父亲");
}
}
public class Son extends Father{
public void show() {
System.out.println("儿子");
}
}
public class Daughter extends Father{
public void show() {
System.out.println("女儿");
}
}
public class Test {
public static void main(String[] args) {
Father s = new Son();
Father d = new Daughter();
Son s1 = (Son)s;
s1.show();
Daughter d1 = (Daughter)s;
d1.show();
}
}
这同样是一个有bug的代码。请仔细观察错误的位置。
main()方法中,在Daughter d1=(Daughter) s;这句代码里我们发现 s是Son类的对象,它和Daughter类一样,继承的是Father类,那我们回头看一下上面的注意点就不难发现 ----两个继承同样父类的子类不能转型。
封装
概述
封装是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问修改。
优点
① 良好的封装能够减少耦合。--与继承所带来的让类之间产生千丝万缕的联系所不同,封装的目的是尽量减少联系。
② 类内部的结构可以自由修改。
③ 可以对成员变量进行更精确的控制。
④ 隐藏信息,实现细节。
⑤ 外部成员无法修改已封装好的程序代码。
应用
注意:
① 属性用private权限修饰符修饰 表示最小的访问权限(只能在同类中直接访问)
② 设置属性的get/set方法,用于其他类间接访问该属性。
案例
上文中继承的案例同样可以用于此。
public class Vehicle {
private int wheels; //private 修饰变量
private double weight;
//两个构造方法
public Vehicle() {
}
public Vehicle(int wheels, double weight) {
this.wheels = wheels;
this.weight = weight;
}
//每个private变量的get/set方法
public int getWheels() {
return wheels;
}
public void setWheels(int wheels) {
this.wheels = wheels;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
//重写的toString方法
@Override
public String toString() {
return "Vehicle{" +
"wheels=" + wheels +
", weight=" + weight +
'}';
}
}
分析:实体变量中将对象中的成员变量进行私有化,外部程序是无法访问的。但是我们对外提供了访问的方式,就是set和get方法。
对于这样一个实体对象,外部程序只有赋值和获取值的权限,是无法对内部进行修改,因此我们还可以在内部进行一些逻辑上的判断等,来完成我们业务上的需要。
到这里应该就明白封装对于我们的程序安全性来说是多么重要了吧!
本期三大特征的介绍就到这里,我们下期再见哦!