super关键字(续)
//----------------------------------父类
public class Animal {
private String name;
private String type;
public Animal(){
System.out.println("父类的无参构造");
}
public Animal(String name,String type){
this.name = name;
this.type = type;
System.out.println("父类的有参构造");
}
public void set(String name,String type) {
this.name = name;
this.type = type;
System.out.println("父类的set()方法");
}
public String get() {
System.out.println("父类的get()方法");
return name +" "+ type;
}
}
//----------------------------------子类
public class Dog extends Animal {
public Dog(){
System.out.println("子类的无参构造");
}
public Dog(String name,String type){
// super(name,type);
System.out.println("子类的有参构造");
}
public void set(String name,String type){
//super.set(name,type);
System.out.println("这是set()方法的重写");
}
}
//----------------------------------测试类
public class Animal_Test {
public static void main(String[] args) {
System.out.println("mian方法");
Dog dog = new Dog("小黄","泰迪");
System.out.println(dog.get());
dog.set("小白","中华田园犬");
System.out.println(dog.get());
}
}
/*
mian方法
父类的无参构造
子类的有参构造
父类的get()方法
null null
这是set()方法的重写
父类的get()方法
null null
*/
在上述代码中我们可以看到在我们调用的子类中的有参构造方法和set()方法并没有达到我们想要的结果,下面我们把注释掉的super(name,type);和//super.set(name,type);取消注释
下面是取消注释掉得到的结果
mian方法
父类的有参构造
子类的有参构造
父类的get()方法
小黄 泰迪
父类的set()方法
这是set()方法的重写
父类的get()方法
小白 中华田园犬
在之前的博客中我们也提到了,super关键字不是父类的构造器,而是子类和父类特征的桥梁,通过super我们可以实现对父类中private修饰的成员属性进行操作
与super()在构造器有同样奇特操作的还有this();
下面通过一段代码展示this()的使用
//----------------------------------父类
public class Animal {
private String name;
private String type;
public Animal(){
System.out.println("父类的无参构造");
}
public Animal(String name,String type){
this.name = name;
this.type = type;
System.out.println("父类的有参构造");
}
public void set(String name,String type) {
this.name = name;
this.type = type;
System.out.println("父类的set()方法");
}
public String get() {
System.out.println("父类的get()方法");
return name +" "+ type;
}
}
//----------------------------------子类
public class Dog extends Animal {
public Dog(){
this("黑子","德牧");
System.out.println("子类的无参构造");
}
public Dog(String name,String type){
super(name,type);
System.out.println("子类的有参构造");
}
public void set(String name,String type){
super.set(name,type);
System.out.println("这是set()方法的重写");
}
}
//就是在前面的代码Dog类的无参构造方法下添加了this("黑子","德牧");
//----------------------------------测试类
public class Animal_Test {
public static void main(String[] args) {
System.out.println("mian方法");
Dog dog = new Dog();
System.out.println(dog.get());
}
}
/* mian方法
父类的有参构造
子类的有参构造
子类的无参构造
父类的get()方法
黑子 德牧
*/
这样就可以完成对于一个使用无参构造器new的子类型对象进行赋上开发者想要的初始值了
这里的this()和super()一样只能用于构造方法,特别是只能用于无参的构造方法,毕竟用于有参的子类构造方法,不符合常理,而且this()和super(),不能同时使用,鱼和熊掌不能兼得(字面意思),同样this()也只能是构造方法中的第一句Java语句。
4、Object类
在之前的博客中我们有提到所有没有显示父类的类型都有一个隐藏的父类那就是Object类了
它是所有看不见父类的类型的父类,如果一个类型继承了其他类型,它的父类没有继承其它的类,那么它的父类的父类就是Object,因为在Java中只支持单继承,即没有三性家奴(好像也不是特别恰当),这就造就了Object成了所有类型的最高层的父类
//补充
class A extends class B{}
class B extends class C{}
class C extends class D{}
class D extends class E{}
/*在上述继承中我们可以得知 A继承了B,B继承了C,C继承了D,D继承了E
因为继承关系子类可以调用父类中的成员属性和没有被private修饰的成员方法
所以A其实拥有了B、C、D、E类的特征但是它的父类只能是B
*/
所以也就是说所有的类都有Object类的特征
测试代码如下:
public class ObjectTest {
public static void main(String[] args) {
ObjectTest obj = new ObjectTest();
System.out.println(obj);
}
}
/*输出的结果
ObjectTest@1e643faf
*/
//对比
public class ObjectTest {
public static void main(String[] args) {
ObjectTest obj = new ObjectTest();
System.out.println(obj.toString());
}
}
/*输出的结果
ObjectTest@1e643faf
*/
是一样的,你没看错
在查阅Java jdk的源码中我们找到了Object类,也在Object类中看到了toString()方法,这个方法的返回值是
getClass().getName() + “@” + Integer.toHexString(hashCode());也就是上面我们看到的结果那样,但是在ObjectTest这个类中我们并没有定义toString()这个方法,但是无论是我们没有直接调用和直接调用都产生了同样的结果,所以这个方法是从那里来的呢?我们没有看到显示的继承关系,这时我们可以肯定这个类有个隐藏的父类,那就是Object类。综上,Obejct类是所有类的基类。
5、重写(override)
在一开始的代码中我们用到了重写,有构造方法的重写也有成员方法的重写
为什么要重写呢?
重写一般发生在父类中存在的业务逻辑无法完成子类所能达到的效果时,就是平时我们打游戏的时候因为版本的更新我们之前的那一套玩法无法在现有版本更加的牛X,所以我们为了跟上版本就不得不再重新研究一套适合这个版本的玩法,当然我们这套玩法还是基于这个游戏,基于这个游戏里面的角色。关于重写:
只发生再有继承关系的子类中;
方法名与父类的相同;
参数列表相同;
参数在参数列表中的顺序相同;
方法的返回值相同;
private修饰的方法无法被重写;
重写后的方法权限只能提高不能降低(private->default->protected->public),要么维持原有权限,要么放权。为什么要说重写和继承呢?
因为继承的耦合度过高,要是父类的业务逻辑变更也会导致子类的业务逻辑受到影响,不适合在数以百计,数以万计的类存在的实际设计中,所以,我们为了让父类的业务逻辑变更时或者是子类的业务逻辑变更时更好操作,用了重写,这也符合我们七大原则中的开闭原则(OCP)。当然最重要的是要说多态。
6、多态
多态:面向对象三大特征之一
多态的灵魂:父类型的引用指向子类型的对象,当然这里面少不了继承和重写。
这在之前的博客中我们也有说明,而完成这一指向的关键是继承关系下两个类通过super关键字完成了这一伟大壮举,还有两个关键的概念:静态绑定和动态绑定。
//下面是一段对多态简单表述的一段代码
//----------------------------------父类
public class Animal {
private String name;
public Animal(){}
public Animal(String name){
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void eat(){
System.out.println(getName() + "吃东西");
}
}
//----------------------------------子类
public class Dog extends Animal{
public Dog(){}
public Dog(String name){
super(name);
}
@Override
public void setName(String name) {
super.setName(name);
}
@Override
public String getName() {
return super.getName();
}
@Override
public void eat() {
System.out.println("吃骨头");
}
public void woof(){
System.out.println(getName() + "在汪汪叫");
}
}
public class Cat extends Animal {
public Cat(){}
public Cat(String name){
super(name);
}
@Override
public void setName(String name) {
super.setName(name);
}
@Override
public String getName() {
return super.getName();
}
@Override
public void eat() {
System.out.println("吃鱼");
}
}
//----------------------------------测试类
public class Me {
public void feed(Animal animal){
System.out.print("我在喂" + animal.getName());
animal.eat();
}
}
public class Test {
public static void main(String[] args) {
Animal animal1 = new Dog();//向上转型,自动转换
Animal animal2 = new Cat();
animal1.setName("xxx");
animal2.setName("ooo");
Me i = new Me();
i.feed(animal1);
i.feed(animal2);
Dog dog = (Dog)animal1;//向下转型,强制转换
dog.woof();
}
}
/*输出结果
我在喂xxx吃骨头
我在喂ooo吃鱼
xxx在汪汪叫
*/
在上述的过程中我们使用了向下转型,这种需要强转的方式,早在基础数据类型的时候我们就知道强制转换肯定有风险
//修改Me类
public class Me {
public void feed(Animal animal){
System.out.print("我在喂" + animal.getName());
if
Dog dog = (Dog)animal;
dog.eat();
}
}
/*
我在喂xxx吃骨头
吃骨头
我在喂ooo吃鱼
Exception in thread "main" java.lang.ClassCastException: class Test02.Cat cannot be cast to class Test02.Dog (Test02.Cat and Test02.Dog are in unnamed module of loader 'app')
at Test02.Me.feed(Me.java:7)
at Test02.Test.main(Test.java:11)
*/
出现经典的异常 " Exception in thread “main” java.lang.ClassCastException "
为了避免着一异常我们可以使用instanceof关键字
//解决上述出现异常的问题
public class Me {
public void feed(Animal animal){
System.out.print("我在喂" + animal.getName());
if (animal instanceof Dog) {
Dog dog = (Dog)animal;
dog.eat();
}else if(animal instanceof Cat){
Cat cat = (Cat)animal;
cat.eat();
}else animal.eat();
}
}
以上是我对多态的认识,但是我感觉写的还是有点问题,我会继续改进的,先到这里吧,嘿嘿