Java面向对象知识点(下)

本文详细阐述了Java中的类继承机制,包括子类如何继承父类、方法的重写、super关键字的使用、final关键字的作用,以及抽象类、接口和多态的原理。此外,还介绍了对象类型转换、instanceof关键字、Object类、内部类和Java异常处理,包括编译时异常与运行时异常的区别以及自定义异常的创建。
摘要由CSDN通过智能技术生成

1.类的继承

1.1继承的概念

类的继承指在一个现有类的基础上构建一个新的类,构建出来的类称为子类,现有类称为父类。

使用extends关键字声明继承关系,语法格式如下:

class 父类{
    ...
}
class 子类 extends 父类{
    ...
}

例如:

class Animal{
    private String name;
    public String getName(){
        return name;
    }
    public String setName(String name){
        this.name = name;
    }
}

class Dog extends Animal{
}

public class Test{
    public static void main(String[] args){
        Dog dog = new Dog();
        dog.setName("牧羊犬");
        System.out.println(dog.getName());
    }
}     

子类没有定义任何属性和方法,但在继承父类的时候会继承父类的成员,但不能直接访问父类中的私有成员。

子类也可以定义自己的属性和方法,例如:

class Animal{
    private String name;
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name = name;
    }
}

class Dog extends Animal{
    private String color;
    public String getColor(){
    return color;
    }
    public void setColor(String color){
        this.color = color;
    }
}

public class Test{
    public static void main(String[] args){
        Dog dog = new Dog();
        dog.setName("牧羊犬");
        dog.setColor("黑色");
        System.out.println(dog.getName(),dog.getColor());
}     

注意:

Java中一个类只有一个直接父类,多个类可以继承一个父类,一个类的父类可以继承另一个父类。

1.2方法的重写

子类对继承的方法进行修改,即对父类的方法进行重写。

重写的方法不能改变方法名、参数列表和返回值类型,且不能拥有比父类更加严格的访问权限

class Animal{
    void shout(){
        System.out.println("动物叫声");
    }
}

class Dog extends Animal{
    void shout(){
        System.out.println("汪汪汪...");
    }
}

public class Test{
    public static void main(String[] args){
        Dog dog = new Dog();
        dog.shout();
}     

最终的输出结果为“汪汪汪...”。

注意:重写父类的方法后,子类对象无法直接访问父类被重写的方法,可以用super关键字解决。

2.super关键字

super关键字可以在子类中调用父类的普通属性、方法和构造方法,具体格式如下:

super.成员变量
super.成员方法(参数1,参数2...)
super(参数1,参数2...)

(1)子类可以通过super关键字访问父类中的成员变量和成员方法,如:

class Animal{
    String name = "牧羊犬";
    void shout(){
        System.out.println("动物叫声");
    }
}

class Dog extends Animal{
    public void shout(){
        super.out();
    }
    public void printName(){
    System.out.println(super.name);
    }
}

public class Test{
    public static void main(String[] args){
        Dog dog = new Dog();
        dog.shout();
        dog.printName();
}     

(2)子类可以通过super关键字访问父类中的构造方法,如:

class Animal{
    private String name;
    private int age;
    public Animal(String name, int age){
        this.name = name;
        this.age = age;
    }
    //setter和getter方法...
}

class Dog extends Animal{
    private String color;
    public Dog(String name, int age, String color){
        super(name,age);
        this.setColor(color);
    }
    //getter方法...
    public void setColor(String color){
        this.color = color;
    }
}

注意:通过super调用父类构造方法的代码必须位于子类构造方法第一行,且只能出现一次

this和super不可以同时出现再构造方法中,因为二者都要求在首行。

3.final关键字

使用final修饰的类不能有子类,修饰的方法不能被子类重写,修饰的变量是常量,不可修改。

使用final声明变量时要求全部的字母大写。

如果变量使用public static final声明,则该变量将成为全局变量,如:

public static final String NAME = "Zhang";

4.抽象类和接口

4.1抽象类

抽象方法是使用abstract关键字修饰的成员方法,只需声明不需实现。包含抽象方法的类是抽象类,使用abstract关键字修饰,例如:

abstract class Animal{
    abstract void shout();
}

class Dog extends Animal{
    void shout(){
        System.out.println("汪汪汪...");
    }
}

注意:如果一个非抽象类继承了抽象类,该子类必须实现抽象类中全部抽象方法

使用abstract关键字修饰的抽象方法不能使用private修饰,因为必须被子类实现。

4.2接口

所有方法都是抽象的抽象类可以被定义为接口。

Java使用接口的目的是克服单继承的限制一个接口可以有多个父接口,但不允许继承抽象类。

接口使用interface关键字声明接口,语法格式如下:

public interface 接口名 extends 接口1,接口2...{
    public static final 数据类型 常量名 = 常量值;
    public abstract 返回值类型 抽象方法名称(参数列表);
}

接口除了可以包括抽象方法外,还可以包括默认方法和静态方法,这两种方法都允许有方法体。

接口中的变量默认使用“public static final”修饰,即全局常量,定义的方法默认使用“public abstract”修饰,即静态方法

注意:如果接口声明为public,则其中所有的常量和方法全部为public。

使用implements关键字实现接口和其中的所有抽象方法,语法格式如下:

修饰符 class 类名 implements 接口1, 接口2,...{
    ...
}
interface Animal{
    void shout();
}

interface Action{
    void eat();
}

class Dog implements Animal,Action{
    public void shout(){
        System.out.println("汪汪汪...");
    }
    public void eat(){
        System.out.println("骨头");
    }
}

也可以实现一个类既实现接口又继承抽象类,如:

interface Animal{
    void shout();
}

abstract class Action{
    public abstract void eat();
}

class Dog extends Action implements Animal{
    public void shout(){
        System.out.println("汪汪汪...");
    }
    public void eat(){
        System.out.println("骨头");
    }
}

5.多态

多态有两种形式:方法的重载(方法多态),方法的重写(对象多态)

5.1对象类型转换

对象类型转换主要有两种情况:

(1)向上转型:子类对象->父类对象

父类类型 父类对象 = 子类实例;
Dog dog = new Dog();
Animal an = dog;
an.shout();

注意:发生向上转型后,调用的方法为被子类重写后的方法。

父类方法无法调用只在子类中定义,没有在父类中定义过的方法。

(2)向下转型:父类对象->子类对象

父类类型 父类对象 = 子类实例;
子类类型 子类对象 = (子类) 父类对象;

不能直接写为:

Dog dog = (Dog) new Animal;

注意:向上转型程序会自动完成,向下转型要指名转型的子类类型

5.2instanceof关键字

使用instanceof关键字判断一个对象是否是某个类的实例,如果是,则返回true,否则返回false,语法格式如下:

对象 instanceof 类
class Animal{
    ...
}
class Dog extends Animal{
    ...
}
public class Test{
    public static void main(String[] args){
        Animal a1 = new Dog();
        System.out.println(a1 instanceof Animal);
        System.out.println(a1 instanceof Dog);
}

最终运行结果都为true。

6.Object类

定义一个类时,如果没有使用extends关键字显式指定父类,则默认继承Object类

Object类是所有类的父类,因此通常被称为超类,其中定义了一些方法,常用的如下:

7.内部类

在一个类的内部定义的类称为内部类,根据内部类的位置、修饰符和定义方式的不同可分为成员内部类、静态内部类、局部内部类(方法内部类)和匿名内部类

7.1成员内部类

成员内部类可以访问外部类的所有成员

如果想通过外部类访问成员内部类,需要通过外部类创建内部类对象,语法格式如下:

外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
class Outer{            //外部类
    int m = 0;
    class Inner{        //成员内部类
        int n = 1;
        void show1(){
            System.out.println(m);
        }
    }
    Inner inner = new Inner();
    System.out.println(n);
}

public class Test{
    public static void main(String[] args){
        Outer.Inner inner = new Outer().new Inner();
        System.out.println(inner.n);
    }
}

7.2静态内部类

静态内部类是使用static关键字修饰的成员内部类

静态内部类只能访问外部类的静态成员

如果想通过外部类访问静态内部类,可以跳过外部类直接访问,语法格式如下:

外部类名.静态内部类名 变量名 = new 外部类名().静态内部类名();

7.3局部内部类

局部内部类定义在方法中,有效范围只限于方法内部

局部内部类可以访问外部类的所有成员

局部内部类的成员只能在所述方法中访问,不能被外部类访问。

class Outer{            //外部类
    int m = 0;
    void test(){
        class Inner{    //局部内部类
            int n = 1;
            void show(){
                System.out.println(m);
            }
        }
    }
}

7.4匿名内部类

匿名内部类是没有名称的内部类,是实现接口的一种简便写法一般用于只使用一次的接口

创建匿名内部类的基本写法如下:

new 父接口(){
    //匿名内部类实现部分
}
interface Animal{
    void shout();
}

public class Test{
    public static void main(String[] args){
        interface Aniaml = new interface Animal(){    //匿名内部类
            @Override
            public void shout(){
                System.out.println("喵喵喵...");
            }
        };
    }
}

8.异常

Java以异常类的形式对程序运行的过程中的各种非正常情况进行封装,通过异常处理机制对程序运行时发生的各种问题进行处理。

Java提供大量异常类,这些类都继承自java.lang.Throwable类。

Throwable类有两个直接子类Error和Exception。

Errow代表程序中的错误,仅靠修改程序本身不能恢复执行。

Exception代表程序中的异常,程序本身可以处理的错误,RuntimeException及其子类表示运行时异常,其他子类表示编译时异常。

Trowable类中常用的方法如下:

8.1异常捕获

异常捕获是对异常进行处理的方式,使用try...catch语句实现,具体语法格式如下:

try{
    //程序代码块
}catch(Exception类及其子类 e){
    //对该类的处理
}

catch代码块对异常处理完毕后,程序会向下执行。try代码块中发生异常语句后面的语句不会被执行。

如果希望语句无论程序是否异常都要执行,可在try...catch语句后加finally代码块,如:

public class Test{
    public static void main(String args[]){
    try{
        int result = divide(4, 0);
    }catch(Exception e){
        System.out.println(e.getMessage());
        return;
    }finally{
        System.out.println("finally代码块");
    }

    public static int divide(int x, int y){
        int result = x / y;
        return result;
    }
}

finally代码块中的代码不受return语句的影响,因此程序设计时常用 finally代码块处理完成必须要做的事,例如释放系统资源。

注意:如果在try...catch中执行了System.exit(0)语句,finally中的代码不会执行,因为System.exit(0)语句代表退出当前Java虚拟机。

8.2throws关键字

在方法后使用throws关键字声明抛出异常,这样调用者在调用方法时就明确知道该方法是否有异常,并且必须在程序中对异常进行处理,否则编译不通过,语法格式如下:

修饰符 返回值类型 方法名(参数1, 参数2...)throws 异常类1, 异常类2...{
    //方法体
}
public class Test{
    public static void main(String args[]){
    try{
        int result = divide(4, 0);
    }catch(Exception e){
        e.printStackTrace();
    }

    public static int divide(int x, int y)throws Exception{
        int result = x / y;
        return result;
    }
}

如果不知道如何处理声明抛出的异常,也可以使用throws关键字继续将异常抛出,程序也能编译通过。但是程序一旦发生异常,且异常没有被处理,程序就会非正常终止。

8.3编译时异常与运行时异常

1.编译时异常

Exception类中除了RuntimeException类及其子类,其他子类都是编译时异常(checked异常)。

编译时异常的特点是Java编译器会对异常进行检查,如果出现异常就必须进行处理,否则程序无法通过编译。有两种方式处理:

(1)使用try...catch语句对异常进行捕获处理。

(2)使用throws关键字声明抛出异常,调用者对异常进行处理。

2.运行时异常

RuntimeException类及其子类都是运行时异常

运行时异常的特点是Java编译器不会对异常进行检查,即异常没有处理也能编译通过。

运行时异常一般由程序中的逻辑错误引起,程序运行时无法恢复,例如数组角标越界。

8.4自定义异常

Java允许用户自定义异常,但自定义的异常类必须继承自Exception类或其子类。实际开发中,如果没有特殊要求,自定义的异常类只需继承Exception类,在构造方法中使用super语句调用Exception的构造方法即可,例如:

public class DivideByMinusException extends Exception{
    public DivideByMinusException(){
        super();                //调用Exception无参的构造方法
    }
    public DivideByMinusException(String Message){
        super(message);         //调用Exception有参的构造方法
    }                                                   
}

自定义异常类中使用throws关键字在方法中声明异常的实例对象,语法格式如下:

public class Test{
    public static void main(String args[]){
    try{
        int result = divide(4, -2);
    }catch(DivideByMinusException e){
        e.printStackTrace();
    }

    public static int divide(int x, int y)throws DivideByMinusException{
        if(y<0){
            throw new DivideByMinusException("除数是负数");
        }
        int result = x / y;
        return result;
    }
}
  • 24
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值