Java高级类特性(一)

Wesley13
• 阅读 702

一、继承性

Java高级类特性(一)

1)继承的使用:权限修饰符 class A extends B{};
2)子类:A 父类(基类 SuperClass):B
3)子类继承父类后,父类中声明的属性、方法,子类都可以获取到明确:当父类中有私有的属性或方法时,子类同样可以获取到,只是由于封装性的设计,使得子类不可以直接调用罢了。
4)子类除了通过继承,获取父类的结构之外,还可以定义自己的特有的成分。extends:子类是对父类功能的“拓展”,明确子类不是父类的子集
5)java中类的继承性只支持单继承,一个类只能继承一个父类,但一个父类可以有多个子类。
6)子父类是相对而言的概念。
7)子类继承父类,在创建子类的对象的时候会先调用父类的构造器再调用子类的构造器。

二、方法的重写

子类扩展(extends)了父类,子类是一种特殊的父类。子类可以获得父类所有的属性和方法,达到代码复用的目的。子类总以父类为基础增加新的属性和方法。但是有时候我们还需要重写(覆盖)父类的方法。
子类覆盖父类的方法遵循的是“两同两小一大”原则。两同指的是方法名和形参列表相同。两小指的是子类方法的返回值类型要小于或等于父类被覆盖方法的返回值,子类方法声明抛出的异常应比父类方法抛出的异常要小或相等。一大指的是子类方法的访问权限应该比父类方法要大或相等。尤其要注意的是,覆盖方法和被覆盖方法要么都是类方法,要么都是实例方法,不能一个是类方法,一个是实例方法,否则回报编译错误。代码如下:

class SuperClass{
    public  void test(){}
    public void test1(){}
}
 
class  SubClass extends SuperClass{
    //注释掉了,编译时会报This static method cannot hide the instance method from SuperClass
    //public static void test(){}   
    @Override
    public void test1(){}
}

如果父类方法具有private访问权限,则该方法对子类是隐藏的,子类是不能访问到的,也不能覆盖该方法。如果子类定义了与父类private方法相同的方法名,则该子类只不过是新定义了一个方法而已。

三、权限修饰符

1、Java中有四种访问权限,private、default(一般省略)、public、protected。

1.private: Java语言中对访问权限限制的最窄的修饰符,一般称之为“私有的”。被其修饰的属性以及方法只能被该类的对象访问,其子类不能访问,更不能允许跨包访问。
2.default:即不加任何访问修饰符,通常称为“默认访问权限“或者“包访问权限”。该模式下,只允许在同一个包中进行访问。
3.protected: 介于public 和 private 之间的一种访问修饰符,一般称之为“保护访问权限”。被其修饰的属性以及方法只能被类本身的方法及子类访问,即使子类在不同的包中也可以访问。
4.public: Java语言中访问限制最宽的修饰符,一般称之为“公共的”。被其修饰的类、属性以及方法不仅可以跨类访问,而且允许跨包访问。
这里需要注意的是,所谓的访问,可以分为两种不同方式:第一,通过对象实例访问;第二,直接访问。
比如说,某父类protected权限的成员,子类是可以直接访问的,换一种说话是子类其实继承了父类的除了private成员外的所有成员,包括protected成员,所以与其说是子类访问了父类的protected成员,不如说子类访问了自己的从父类继承来的protected成员。另一方面,如果该子类与父类不在同一个包里,那么通过父类的对象实例是不能访问父类的protected成员的。

2、下面用表格来展示四种修饰符的访问权限范围

权限

类内

同包

不同包子类

不同包非子类

private

×

×

×

default

×

×

protected

×

public

四、super关键字的使用

package com.test.java;
/*
 * super可以用来修饰属性、方法、构造器
 * 1)当子类与父类中有同名的属性时,可以通过"super.属性"显式的调用父类中声明的属性。用"this.属性"调用子类中声明的属性
 * 2)当子类重写父类的方法以后,在子类中想再显式的调用父类的被重写的方法,需要用"super.方法来调用"
 * 3)super修饰构造器:通过在子类中使用"super(形参列表)"来显式的调用父类的构造器
 *         >在构造器内部,"super(形参列表)"必须要声明在首行
 *         >在构造器内部,"this.(形参列表)"与"super(形参列表)"只能出现一个
 *         >当构造器中,不显式的调用this()或者super()其中任何一个,默认调用的是父类的空参构造器
 *             如果父类没有声明空参构造器,或者只声明了带参数的构造器(这时空参构造器自动作废),在子类
 *             中会报错
 *         建议:在设计一个类时,尽量提供一个空参构造器。
 */
public class Person {
    public String name;
    
    public Person() {//父类构造器
        this.name = "Father";
        System.out.println(this.name);
    }
    
    public void eat() {
        System.out.println("父类吃饭");
    }
}
class Student extends Person{
    public String name;
    
    public Student() {//子类构造器,经过main方法测试,调用子类构造器之前会自动调用父类构造器
        //相当于这里有一个 Super();
        this.name = "Son";
        super.name = "SuperFather";//在子类中调用父类的
        System.out.println(this.name+super.name);
    }
    public void eat() {
        System.out.println("子类吃饭");
        super.eat();//在子类中用super调用父类的重名方法,重写(覆盖)并不等于将父类的方法删除掉。
    }
}

五、子类对象实例化

class Creature{
       public Creature(){
    System.out.println("Creature无参数的构造器");    
       }
}
class Animal extends Creature{
       public Animal(String name){
    System.out.println("Animal带一个参数的构造器,该动物的name为" + name);
       }
       public Animal(String name , int age){
    this(name);
    System.out.println("Animal带两个参数的构造器,其age为" + age);
       }
}
public class Wolf extends Animal{
       public Wolf(){
    super("灰太狼", 3);
    System.out.println("Wolf无参数的构造器");
       }
       public static void main(String[] args){
    new Wolf();
       }    }

从创建Wolf对象开始,调用Wolf构造器,Wolf构造器调用父类Animal的两个参数的构造器,两个参数的构造器再调用一个参数的构造器,一个参数的构造器再调用父类Creature的构造器,Creature构造器调用Object类中的构造器,然后再逆向执行回来,最后一个被调用的构造器最先执行,依次向下执行构造器中的内容,像对象中的toString方法等就是再Object类中的某个方法,任何一个类调用构造器都会以最后一个Object类结束。

六、多态性

package com.xijian.java;
/*
 * 多态的应用举例
 * 总结:通过向上转型来引用父类方法(在子类未重写方法的前提下),通过向下转型来引用子类独有的方法
 * 向下转型实际就是在栈空间声明一个子类引用类型的变量指向栈空间的父类引用对象,通过父类引用对象进而指向堆空间,对对象进行操作。
 * 访问权限是由引用变量类型决定的。
 */
public class TestAnimal {
    public static void main(String[] args) {
        Animal a = new Dog();//可以扩大对象被调用的权限
        Animal b = new Cat();//可以扩大对象被调用的权限
        TestAnimal test = new TestAnimal();
        test.func(a);
        test.func(b);
    }
    public void func(Animal a) {
        a.eat();
        a.jump();
        
        if(a instanceof Dog) {
            Dog d = (Dog)a;//向下转型,用新的引用类型去引用子类存在而父类不存在的方法
            d.say();
        }
        if(a instanceof Cat) {
            Cat c = (Cat)a;//向下转型,用新的引用类型去引用子类存在而父类不存在的方法
            c.say();
            c.name = "1";
            System.out.println(a.name);//通过测试可以看出,向下转型使用新的引用类型可以对子类对象进行操作
        }
    }
}
class Animal{
    String name;
    int age;
    
    public void eat() {
        System.out.println("进食");
    }
    public void jump() {
        System.out.println("jump");
    }
    
}
class Dog extends Animal{
    public void eat() {
        System.out.println("狗进食");
    }
    public void jump() {
        System.out.println("狗急跳墙");
    }
    public void say() {
        System.out.println("狗叫");
    }
}
class Cat extends Animal{
    public void eat() {
        System.out.println("猫进食");
    }
    public void jump() {
        System.out.println("猫跳");
    }
    public void say() {
        System.out.println("猫叫");
    }
}

多态性:多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

1)如果我们定义了一个指向子类的父类引用类型,那么它除了能够引用父类的共性外,还可以使用子类强大的功能,这就是向上转型。
父类名称 引用对象名称 = new 子类对象名称();
指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。()
2)如果在向上转型之后想访问子类中独有的方法,需要向下转型,向下转型实际就是在栈空间声明一个子类引用类型的变量指向栈空间的父类引用对象,通过父类引用对象进而指向堆空间,对对象进行操作。
子类名称 新引用对象名称 = (子类名称)需转型的对象名;
3)子类对象的多态性,并不适用于属性!
在调用属性的时候,只是看的是调用对象的引用类型,如果这个对象的引用类型是父类的,那么调父类的属性,如果是个子类的引用类型,则调子类对应的属性,并不存在多态性。
4)判断对象属于哪种类型的
if(obj instanceof class){}
其返回true情况如下
1.obj是class类的对象
2.obj是class类子类的对象

多态性在Java上有两种体现
①方法的重载和重写:同名方法可以通过形参列表的不同和子父类的继承关系来同时显示。
②对象的多态性:子类的对象可以赋给父类/父接口的引用。

七、所有的类的顶级类Object

package com.xijian.java;
 
public class Testequals {
    public static void main(String[] args) {
        //==
        //1.基本数据类型:根据基本数据类型的值判断是否相等。相等返回true,否则返回false
        //注:两端数据类型可以不同,在不同的情况下也可以返回true
        int i = 12;
        int j = 12;
        System.out.println(i==j);//true
        char c = 12;
        System.out.println(i==c);//true
        float f = 12.0F;
        System.out.println(i==f);//true
        
        int k = 65;
        char a = 'A';
        System.out.println(k==a);//true
        //2.引用数据类型:比较引用类型变量的地址值是否相等。
        Object obj1 = new Object();
        Object obj2 = new Object();
        Object obj3 = new Object();
        obj3 = obj1;
        System.out.println(obj1==obj2);//false
        System.out.println(obj1==obj3);//true
        //equals():①只能处理引用类型对象,并且比较的是两个对象的地址值是否相等
        System.out.println(obj1.equals(obj2));
        System.out.println(obj1.equals(obj3));
        //像String类 包装类 File类 Date类重写了Object类里的equals方法
        //比较的是两个对象中的具体内容是否相同
        String str1 = new String("AA");
        String str2 = new String("AA");
        System.out.println(str1.equals(str2));//true
    }
}

Object是Java中所有类的顶级类。
①在Java中,==表示等于,=表示赋值。
当==两侧比较的是基本数据类型时,由基本数据类型的值判断二者是否相等,相等则返回true,不等在返回false。需要注意的是,两侧的基本数据类型即使类型不同,也会返回true,如:int i =65,char j=12;char a ='A';则i==j==a全部返回true。
当两侧是引用数据类型时,两侧比较的是引用变量的地址值,相等返回true,不等返回false。
②equals方法
equals方法只可以处理引用数据类型的变量,在object类中,equals方法仍然是比较两个引用变量的地址值是否相同;所以要想用equals方法比较object类子类的实体内容,就必须要重写object类的equals方法。
③String类在内存中的分析
翻看String类的源代码我们可以知道:它是不可继承的(final修饰类),线程安全的(?????),值不可变(两个成员变量都有final修饰,指针可变),本质上是一个字符数组。
我们知道创建string类对象的时候,一般由三种方式:
使用关键字new,如:String s1 = new String(“myString”);
直接定义,如:String s1 = “myString”;
串联生成,如:String s1 = “my” + “String”
第一种使用关键字new创建的String类对象时,编译程序回先在字符串常量池中查看有没有“myString”这个字符串,若有,则在堆中开辟一块空间存放new出来的实例,指向常量池中的"myString",在栈中开辟一块区域存放s1这个引用变量,指向堆中的new出来的实例;若没有,则在常量池中创建一个"myString"字符串。
第二种方式直接定义过程:在程序编译期,编译程序先去字符串常量池检查,是否存在“myString”,如果不存在,则在常量池中开辟一个内存空间存放“myString”;如果存在的话,则不用重新开辟空间。然后在栈中开辟一块空间,命名为“s1”,存放的值为常量池中“myString”的内存地址
第三种,改变的不是字符串,而是相当于重新创建了一个新的字符串,重新有一个地址值。
相对于new出来的字符串来说,直接赋值的方式效率好,因为它只在字符串常量池开辟了一个内存空间,而new出来的相当于开辟了两个内存空间,耗费内存。
④toString()方法的使用
当我们打印一个引用变量的对象时,默认会调用这个对象的toString方法。
如果对象所在的类没有重写Object中的toString方法,那么调用的就是Object中的toString方法,打印出全类名+@+首地址值。

八、包装类

将8个基础数据类型包装成类之后,就可以调用类中的方法来处理这些数据了。
基本数据类型、包装类、String类之间的转换问题
原则:转换成谁,去谁里边找转换方法或者构造器。
① 基本数据类型和包装数据类型之间的转换:JDK5.0之后加入了自动装箱和拆箱的功能。
②基本/包装数据类型和String数据类型之间的转换
String-->包装数据类型:Integer.parseInt(str)
包装数据类型-->String:i+“ ”

点赞
收藏
评论区
推荐文章
Irene181 Irene181
2年前
一篇文章带你搞懂Python中的继承和多态
一、继承的介绍继承是一种创建新的类的方式,新创建的叫子类,继承的叫父类、超类、基类。继承的特点就是子类可以使用父类的属性(特征、技能)。继承是类与类之间的关系。继承可以减少代码冗余、提高重用性。在现实生活中,继承一般指的是子女继承父辈的财产,如下图:二、如何用继承?1.继承语法Class派生类名(基类名):基类名写在括号里。在继承关系中,已有的,设计好
Jacquelyn38 Jacquelyn38
2年前
你不可不知的JS面试题(第二期)
1、什么是继承?子类可以使用父类的所有功能,并且对功能进行扩展。新增方法改用方法(1)、ES6使用extends子类继承父类的方法。// 父类    class A        constructor(name)            this.name name;                getNa
Bill78 Bill78
3年前
Python的新式类和旧式类
概述:Python中支持多继承,也就是一个子类可以继承多个父类/基类。当一个调用一个自身没有定义的属性时,它是按照何种顺序去父类中寻找的呢?尤其是当众多父类中都包含有同名的属性,这就涉及到新式类和经典类的区别。多继承:classFood(object):23def__init__(self,name,col
Wesley13 Wesley13
2年前
java中多态的实现机制
多态的概念:  简单来说就是事物在运行过程中存在的不同状态,即父类或接口定义的引用变量指向子类或具体实现类的实例对象。程序调用方法在运行期才进行动态绑定,而不是引用变量的类型中定义的方法。多态存在的前提:1、存在继承关系,子类继承父类;2、子类重写父类的方法;3、父类引用指向子类对象。具体实例:1、定义一个父类:Animal
Wesley13 Wesley13
2年前
java向上转型和向下转型1
  在java继承体系中,认为父类(超类)在上层,子类在下层(派生类),向上转型就是把子类对象转成父类对象。1publicclassFather{2publicvoideat(){3System.out.println("我是父类的方法吃。。。。。");4}
Stella981 Stella981
2年前
Python Day24:类的继承、派生、覆盖、super()、绑定、非绑定方法
类的继承、派生、覆盖、super()python类的继承:子类继承父类,只需要在定义类的时候在类名后面加上(父类名)。继承之后,父类的属性方法、子类都可以访问派生:子类继承父类后,自己在父类的基础上,又添加了一些属于自己特性的属性、方法
Wesley13 Wesley13
2年前
Java的类继承
知识点1、继承作用:提高代码的重用性,继承之后子类可以继承父类中的属性和方法减少重复代码条件:子类和父类要满足isa的逻辑关系,才能使用继承。如:苹果isa水果语法:使用extends连接子类和父类。子类extends父类Java是单继承,一个类只能继承一个父类。子类不能继承父类私有的属性,但是可以
Easter79 Easter79
2年前
Swift专题讲解十四——继承
Swift专题讲解十四——继承一、引言      Swift中,一个类可以从另一个类继承方法、属性、下标及其他特性。当一个类继承于另一个类时,这个类被称为子类,所继承的类被称为父类。在Swift中,继承是类区别于其他类型的主要特征。子类除了可以调用父类的属性,下标,方法外,其也可以对父类的属性,下标,方法进
Wesley13 Wesley13
2年前
Java基础知识笔记
Java基础知识笔记6继承6继承继承是一种由已创建的类创建新类的机制,利用继承,我们先创建一个共有属性的一般类,根据一般类再创建具有特殊属性的新类,新类继承一般类的状态和行为,并根据需要增加他自己新的状态和行为,由继承得到的类称为子类,被继承的称为父类。Java中,一个子类只能继承一个父类,不支持多重继承;1继承的基
小万哥 小万哥
2个月前
C# 继承、多态性、抽象和接口详解:从入门到精通
C继承在C中,可以将字段和方法从一个类继承到另一个类。我们将“继承概念”分为两类:派生类(子类)从另一个类继承的类基类(父类)被继承的类要从一个类继承,使用:符号。在以下示例中,Car类(子类)继承了Vehicle类(父类)的字段和方法:示例csharpc