目录
一、继承
继承:是指在一个现有类的基础上去构建一个新的类
class 父类 {
......
}
class 子类 extends 父类 {
......
}
注意
- 类只能单继承,不允许多重继承
- 多个类可以继承一个父类
- 一个类的父类可以再继承另外的父类,即允许多层继承
- 子类不能调用父类的私有方法与属性
1.1 方法重写
在继承中,子类会自动继承父类中定义的方法,但有时会需要对子类继承的方法进行修改,即对父类的方法进行重写
public class Demo01 {
public static void main(String[] args) {
// 创建对象
Lion lion = new Lion();
// 属性和方法:Lion类中定义的属性和方法
lion.name = "狮子";
lion.age = 12;
lion.eat(); // 狮子吃肉
// 类中没有定义属性和方法
HoneyBadger badger = new HoneyBadger();
badger.name = "蜜獾";
badger.age = 8;
badger.eat(); // 蜜獾吃蜂蜜
badger.sleep(); // 动物需要睡觉
}
}
/**
* 父类Animal
*/
class Animal {
// 属性
String name;
int age;
// 方法
public void eat() {
System.out.println("动物需要进食");
}
public void sleep() {
System.out.println("动物需要睡觉");
}
}
/**
* 狮子
*/
class Lion extends Animal {
// 属性
String name;
int age;
// 方法
public void eat() {
System.out.println("狮子吃肉");
}
}
/**
* 蜜獾
* 继承Animal,获取到Animal中的属性和方法
*/
class HoneyBadger extends Animal {
double height;
public void eat() {
System.out.println("蜜獾吃蜂蜜");
}
}
1.2 super关键字
当子类重写父类的方法后,子类对象将无法访问父类被重写的方法,通过super关键字可以在子类中调用父类的成员方法与成员变量
super.成员变量
super.成员方法(参数...)
/*
super 调用普通方法
*/
public class Demo02 {
public static void main(String[] args) {
// 创建对象
Dog d1 = new Dog();
d1.shout();
/* 输出:
动物吼叫
狗汪汪叫
*/
}
}
/**
* 父类Animal
*/
class Animal {
// 属性
String name;
int age;
// 方法
public void shout() {
System.out.println("动物吼叫");
}
}
class Dog extends Animal {
// 属性
String name;
int age;
// 方法
public void shout() {
super.shout();
System.out.println("狗汪汪叫");
}
}
/*
super 调用构造方法
*/
public class Demo03 {
public static void main(String[] args) {
// 创建对象
Dog d1 = new Dog("多多", 5);
d1.introdce(); // 它是多多, 5岁,是个牧羊犬
}
}
/**
* 父类Animal
*/
class Animal {
// 属性
String name;
int age;
// 方法
public Animal(String str, int a) {
this.name = str;
this.age = a;
}
}
class Dog extends Animal {
// 属性
String breed;
// 方法
public Dog(String str, int a) {
super(str, a);
this.breed = "牧羊犬";
}
public void introdce() {
System.out.println("它是" + name + ", " + age + "岁,是个" + breed);
}
}
子类不能重复定义父类已有的属性,否则调用父类方法对属性进行修改不会生效
public class Demo04 {
public static void main(String[] args) {
// 创建对象
Dog d1 = new Dog("多多", 5);
d1.introdce(); // 它是null, 0岁,是个牧羊犬
}
}
/**
* 父类Animal
*/
class Animal {
// 属性
String name;
int age;
// 方法
public Animal(String str, int a) {
this.name = str;
this.age = a;
}
}
class Dog extends Animal {
// 属性
String name; // 重复定义的属性
int age; // 重复定义的属性
String breed;
// 方法
public Dog(String str, int a) {
super(str, a);
this.breed = "牧羊犬";
}
public void introdce() {
System.out.println("它是" + name + ", " + age + "岁,是个" + breed);
}
}
二、final关键字
- 使用final关键字修饰的类,将不可被继承,即不能派生子类
- 使用final修饰的方法不能被子类重写
- 使用final修饰的变量(成员变量和局部变量)是常量,不可被修改
2.1 final关键字修饰的类
// 该程序报错,仅作示例
public class Demo05 {
public static void main(String[] args) {
Dog d1 = new Dog(); // Dog无法继承Animal
}
}
final class Animal {
}
class Dog extends Animal {
}
2.2 final关键字修饰的方法
// 该程序报错,仅作示例
public class Demo06 {
public static void main(String[] args) {
Dog d1 = new Dog();
d1.shout(); // Dog无法使用shout方法
}
}
class Animal {
final void shout() {
System.out.println("动物吼叫");
}
}
class Dog extends Animal {
}
2.3 final关键字修饰的变量
// 该程序报错,仅作示例
public class Demo07 {
public static void main(String[] args) {
final int NUMA = 1;
NUMA = 2; // 变量a无法再次赋值
}
}
注意:final定义的变量全部字母需要大写
三、抽象类和接口
3.1 抽象类
当无法确定将要定义的类的成员方法的确切内容时,可以通过abstract关键字定义抽象类,在类中定义抽象方法
注意:
- 当一个类包含抽象方法,则这个类必定是抽象类
- 抽象类与抽象方法都需要abstract关键字修饰
- 抽象方法不需要实现
- 若一个类继承了抽象类,则该子类必须实现所有的抽象方法
- 抽象方法不能被private关键字修饰,因为抽象方法必须被子类实现
// 抽象方法
abstract 返回值类型 方法名(参数);
// 抽象类
abstract 抽象类名 {
属性;
访问权限 返回值类型 方法名(参数~) {
return 返回值;
}
访问权限 abstract 返回值类型 抽象方法名(参数~);
}
public class Demo08 {
public static void main(String[] args) {
Dog d1 = new Dog();
d1.shout();
}
}
abstract class Animal {
abstract void shout(); // 声明抽象方法
}
class Dog extends Animal {
public void shout() {
System.out.println("狗汪汪叫");
}
}
3.2 接口
若一个抽象类的所有方法都是抽象的,则可以将这个抽象类定义为接口
抽象类可以包括抽象方法、默认方法和静态方法,后两种方法允许有方法体
// 接口语法格式
public interface 接口名 extends 接口1, 接口2, ... {
public static final 数据类型 常量名 = 常量值; // 接口中的变量默认以 public static final 修饰
public abstract 返回值类型 抽象方法名(参数~);// 接口中的方法默认以 public abstract 修饰
}
// 接口的实现类语法格式
修饰符 class 类名 implements 接口1, 接口2, ... {
public abstract 返回值类型 抽象方法名(参数~){
方法实现;
}
}
public class Demo09 {
public static void main(String[] args) {
// 创建对象
Dog d1 = new Dog();
Animal.getAno();
d1.info();
/*
684684
它是牧羊犬, 5岁
*/
}
}
interface Animal {
// 属性
String name = "牧羊犬";
int age = 5;
int ano = 684684;
// 方法
public void info();
static void getAno(){
System.out.println(ano);
}
}
class Dog implements Animal {
// 属性
String breed;
// 方法
public void info() {
System.out.println("它是" + name + ", " + age + "岁");
}
}
如果一个类既实现接口又继承抽象类,其格式为:
修饰符 class 类名 extends 父类名 implements 接口1, 接口2, ... { ...... }
注意:接口不允许继承抽象类,但一个接口可以继承多个接口
public class Demo10 {
public static void main(String[] args) {
// 创建对象
Dog d1 = new Dog();
d1.info();
d1.infoBreed();
/*
它是多多, 5岁
它是牧羊犬
*/
}
}
interface Animal {
// 属性
String name = "多多";
int age = 5;
// 方法
public void info();
}
interface Breed extends Animal {
// 属性
String breed = "牧羊犬";
// 方法
public void infoBreed();
}
class Dog implements Animal, Breed {
// 方法
public void info() {
System.out.println("它是" + name + ", " + age + "岁");
}
public void infoBreed() {
System.out.println("它是" + breed);
}
}
四、多态
多态是指在不同对象调用同一个方法时出现的多种不同行为,其形式有
- 方法的重载
- 对象的多态性(方法重写)
4.1 对象类型的转换
对象向上转型(子类对象 -> 父类对象):
父类类型 父类对象 = 子类实例;
// 向上转型 public class Demo11 { public static void main(String[] args) { // 创建对象 Animal a1 = new Dog(); System.out.println(a1.getClass().getName()); // Day05.Dog 表明属于Dog类 a1.shout(); // 狗汪汪叫 // a1.eat(); // 不通过,子类独有的方法不保留 } } class Animal { // 方法 public void shout() { System.out.println("动物吼叫"); } } class Dog extends Animal { // 方法 public void shout(){ System.out.println("狗汪汪叫"); } public void eat(){ System.out.println("狗进食"); } }
对象向下转型(父类对象 -> 子类对象):
父类类型 父类对象 = 子类实例; 子类类型 子类对象 = (子类)父类实例;
// 向下转型 public class Demo12 { public static void main(String[] args) { // 创建对象 Animal a1 = new Dog(); //向上转型 Dog d1 = (Dog) a1; //向下转型 d1.shout(); // 狗汪汪叫 System.out.println(d1.getClass().getName()); // Day05.Dog 表明属于Dog类 } } class Animal { // 方法 public void shout() { System.out.println("动物吼叫"); } } class Dog extends Animal { // 方法 public void shout(){ System.out.println("狗汪汪叫"); } }
4.2 instanceof 关键字
instanceof关键字判断一个对象是否是某个类(或接口)的实例
对象 instanceof 类(或接口)
public class Demo13 {
public static void main(String[] args) {
// 创建对象
Animal a1 = new Dog();
System.out.println(a1 instanceof Animal); // true
System.out.println(a1 instanceof Dog); // true
// 创建对象
Dog d1 = new Dog();
System.out.println(d1 instanceof Animal); // true
System.out.println(d1 instanceof Dog); // true
// 创建对象
Animal a2 = new Animal();
System.out.println(a2 instanceof Animal); // true
System.out.println(a2 instanceof Dog); // false
}
}
class Animal {
// 方法
public void shout() {
System.out.println("动物吼叫");
}
}
class Dog extends Animal {
// 方法
public void shout(){
System.out.println("狗汪汪叫");
}
}
五、Object类
Object类是java所有类的父类,每个类直接或间接地继承Object类,因此Object类又被称为超类
方法名称 | 方法说明 |
---|---|
boolean equals() | 判断两个对象是否相等 |
int hashCode() | 返回对象的散列码值 |
String toString() | 返回对象的字符串表现形式 |
public class Demo14 {
public static void main(String[] args) {
// 创建对象
Animal a1 = new Animal();
System.out.println(a1.toString()); // Day05.Animal@6d03e736
}
}
class Animal {
// 方法
public void shout() {
System.out.println("动物吼叫");
}
}
六、内部类
6.1 成员内部类
类中除了定义成员变量,成员方法外,还可以定义类,在类中定义的类就称为成员内部类
- 成员内部类可以访问外部类的所有成员
- 若想通过外部类访问内部类,需要先创建外部类实例,再创建内部类实例进行调用
外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
public class Demo15 {
public static void main(String[] args) {
Outer o1 = new Outer();
Outer.Inner i1 = o1.new Inner();
System.out.println(o1.n); // 1
o1.printInfo1(); // 外部类方法
System.out.println(i1.m); // 2
i1.printInfo2(); // 内部类方法
}
}
class Outer{
int n = 1;
void printInfo1() {
System.out.println("外部类方法");
}
class Inner{
int m = 2;
void printInfo2() {
System.out.println("内部类方法");
}
}
}
6.2 局部内部类
局部内部类,也称方法内部类,是定义在某个局部范围内的类,有效范围仅在这一局部范围
- 局部内部类可以访问外部类的所有成员变量和方法
- 局部内部类需要在相应代码块进行实例化后访问
public class Demo16 {
public static void main(String[] args) {
Outer o1 = new Outer();
o1.printInfo1(); // 外部类方法
o1.test(); // 内部类方法
/* 输出:
外部类方法
内部类方法
*/
}
}
class Outer{
int n = 1;
void printInfo1() {
System.out.println("外部类方法");
}
void test() {
int q = 3;
class Inner {
int m = 2;
void printInfo2() {
System.out.println("内部类方法");
}
}
Inner i1 = new Inner(); // 先实例化再使用
i1.printInfo2();
}
}
6.3 静态内部类
6.4 匿名内部类
匿名内部类是没有名称的内部类
- 当想调用某个参数类型为接口类型的方法时,除了传入一个接口实现类外,也可以使用实现接口的匿名内部类
// 1 new 接口() { // 实现匿名内部类 } // 2 new 父类构造器(实参列表) { // 实现匿名内部类 }
注意:
在实例化的时候,我们使用了 new 接口()来创建一个对象,这里看似接口被实例化了(接口不能被实例化),实际上是在实例化一个实现了该接口的匿名对象,也即创建的是一个实现了接口的匿名对象
匿名内部类只能在实例化的地方使用,因为它没有显式的类名,无法在其他地方引用;如果需要在其他地方多次使用相同的实现逻辑,建议考虑创建一个具体的类或实现类来实现相应的接口或继承相应的类
public class Demo17 {
public static void main(String[] args) {
// 创建对象
animalShout(new Animal(){
public void shout(){
System.out.println(name + "汪汪叫"); // 牧羊犬汪汪叫
}
});
}
public static void animalShout(Animal an) {
// 方法
an.shout();
}
}
interface Animal {
String name = "牧羊犬";
// 方法
public void shout();
}
七、异常
异常是指程序安装、运行过程中发生的各种非正常状况
java以异常类的形式对各种非正常情况进行封装,通过异常处理机制对程序运行时发生的各种问题进行处理
java中的异常类都继承自Throwable类,Throwable类有两个直接子类
- Error类(错误类),表示java程序运行时产生的内部错误或资源耗尽的错误
- Exception类(异常类),表示程序本身可以处理的错误
Throwable类常用方法
方法声明 | 功能描述 |
---|---|
String getMessage() | 返回异常的消息字符串 |
String toString() | 返回异常的简单信息描述 |
void printStackTrace() | 获取异常类名和异常信息,以及异常出现在程序中的位置,把信息输出在控制台 |
7.1 try…catch 和 finally
异常捕获
异常捕获借助try…catch语句实现
try{ // 程序代码块 }catch(Exception类及其子类 e){ // 异常处理语句 }
若希望语句无论是否发生异常都要执行可以借助finally代码块实现
public class Demo18 {
public static void main(String[] args) {
try {
System.out.println(divide(3, 0));
}catch(Exception e) {
System.out.println("异常信息:" + e.getMessage());
}finally {
System.out.println("finally代码块");
}
System.out.println("程序即将结束");
/*
异常信息:/ by zero
finally代码块
程序即将结束
*/
}
public static int divide (int a, int b) {
return a / b;
}
}
7.2 throws关键字
throws关键字用于声明方法可能发生的异常并抛出
- 注意throws关键字声明的异常必须被处理(catch代码块),否则会编译错误
- 若不知如何处理抛出的异常,则可对该未处理的异常也进行异常抛出(main函数抛出异常),不过这样程序在遇到异常时会非正常终止
public class Demo19 {
public static void main(String[] args) {
try {
System.out.println(divide(3, 0));
}catch(Exception e) {
System.out.println("异常信息:" + e.getMessage());
}
/*
异常信息:/ by zero
finally代码块
程序即将结束
*/
}
public static int divide (int a, int b) throws Exception {
return a / b;
}
}
7.3 编译时异常与运行时异常
- 编译时异常
除了RuntimeException类及其子类,Exception的其他子类均为编译时异常
编译时异常处理
- 使用try…catch语句对异常进行捕获处理
- 使用throws关键字声明抛出异常,调用者进行异常处理
- 运行时异常
RuntimeException类及其子类都是运行时异常,一般是由于程序逻辑错误引起,程序运行时无法修复
7.4 自定义异常
java允许用户自定义异常,但自定义的异常类必须进程自Exception类或其子类
// 自定义异常类示例
public class DivideByZeroException extends Exception{
public DivideByZeroException(){
super(); // Exception无参构造方法
}
public DivideByZeroException(String message){
super(message); // Exception有参构造方法
}
}
自定义异常类中使用throw关键字在方法中声明异常的实例对象
throw Exception 异常对象
这样声明抛出的异常也需进行异常处理
public class Demo20 {
public static void main(String[] args) {
try{
System.out.println(divide(3, 0));
}catch(Exception e){
System.out.println("异常信息:" + e.getMessage());
}
/*
异常信息:除数为0
*/
}
public static int divide (int a, int b) throws Exception{
if(b == 0) throw new DivideByZeroException("除数为0"); // 创建一个异常类对象
return a / b;
}
}
class DivideByZeroException extends Exception{
public DivideByZeroException(){
super(); // Exception无参构造方法
}
public DivideByZeroException(String message){
super(message); // Exception有参构造方法
}
}