上一章我们谈到了封装,而这里我们就要学习使用继承,但继承会打破封装性,所以对于普通的具体类,我们进行跨包的继承是非常危险的。
在继承中,子类依赖于超类中特定功能的实现,如果超类发生变化,那么子类可能就会被改变,哪怕子类代码并没有改变。
因此,除非我们设计一个类就是被用来做继承,如我们子类对超类有类似于is-a这样的关系,那么我们应该优先使用的其实应该是复合。
上一章我们留下了一个protected关键字,表示继承的类可以直接访问超类中protected所描述的属性或方法。下面我们举例说明它的具体作用域:
同一包下
public class Animal {
private int age = 3;
protected String name = "Animal";
public int getAge(){
return this.age;
}
protected void setAge(int age){
this.age = age;
}
}
public class Dog extends Animal{
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog();
// System.out.println(dog.age);
System.out.println(dog.getAge());
dog.setAge(5);
System.out.println(dog.getAge());
System.out.println(dog.name);
dog.name = "dog";
System.out.println(dog.name);
}
}
>>> out :
3
5
Animal
dog
我们可以发现,Dog类继承了Animal类的属性,但并不能直接操作超类中的私有属性,就像Main类中注释掉的dog.age,因为age属性是私有的,所以必须调用公共方法getAge()获取。但对于protected属性,则可以像自己的公共属性一样操作。
对于不同包:
package one;
public class Animal {
private int age = 3;
protected String name = "Animal";
private String sex = "male";
public int getAge(){
return this.age;
}
protected void setAge(int age){
this.age = age;
}
protected String getSex(){
return this.sex;
}
private void setSex(String sex){
this.sex = sex;
}
}
package two;
public class Cat extends Animal{
}
package two;
public class Main {
public static void main(String[] args) {
Cat cat = new Cat();
// System.out.println(cat.age);
System.out.println(cat.getAge());
// cat.setAge(5);
// System.out.println(cat.name);
// cat.name = "dog";
// System.out.println(cat.name);
}
}
>>>out:3
在不同的包中我们发现,protected关键词标识的方法和属性好像也不能使用了,这是为什么呢?这里我们是在Main类中调用的Cat类的方法,而Cat类继承的protected方法在Main类来看是Animal的,而protected没有public这样的可见性所以无法被Main类使用。
而如果我们在Cat中放入main方法,可以发现,protected标识的属性和方法我们可以正常使用:
public class Cat extends Animal{
public static void main(String[] args) {
Cat cat = new Cat();
// System.out.println(cat.age);
System.out.println(cat.getAge());
cat.setAge(5);
System.out.println(cat.getAge());
System.out.println(cat.name);
cat.name = "dog";
System.out.println(cat.name);
}
}