一.继承概述
继承的特点:
子类可以拥有父类的内容,此外子类还可以拥有自己独有的内容(成员变量和成员方法)
至少需要三个类:父类、子类、主类
格式:
父类的格式:
public class 父类名{
//属性:
//方法:
}
子类的格式:
public class 子类名 extends 父类名{
//继承的父类的属性和方法
//自己所独有的属性和方法
}
主类格式:
public class Main {
public static void main(String[] args) {
}
}
java继承的三大特性:
1.一个父类可以有多个子类
2.一个子类只能有一个父类
3.java中的继承可以是多级继承
4.object是所有类的根节点,除了object类,每个类有且只有一个父类
创建对象:
父类对象创建:
在创建对象时会自动调用构造方法
格式:
父类 变量名 = new 父类();
如类中有重载构造方法,想要调用需要在调用时按形参的提示输入实参
子类对象创建:
会继承父类的所有方法与属性
在创建时会自动调用父类的构造方法和子类的构造方法。
如类中有重载构造方法,想要调用需要在调用时按形参的提示输入实参
格式:
子类 对象名 = new 子类();
二、super关键字
1.调用构造方法
定义:super关键字可以调用父类的构造方法
必须要在子类的方法中调用
格式:
public Zi(){
super();
}
注意:
1.在创建子类对象时,默认书写了super关键字,用以调用父类的构造方法
2.super关键字可以调用重载的构造方法,只需要按照父类的重载构造方法提示的形参,将实参准确输入到super()中就可以
3.想要调用普通构造方法,需要在方法中书写super,且要放到第一位
4.super()只能调用一个方法,在书写super时会报错
5.只要super调用了重载的构造方法,那么默认赠送的super()调用的普通构造方法就会失效
super的三种用法:
1.在子类的成员中访问父类的成员变量
区分局部变量、本类成员变量、父类成员变量重名时的使用:
局部变量:直接写变量名 num
本类的成员变量:this.变量名
父类的成员变量:super.变量名
2.在子类的成员中访问父类的成员方法
3.在子类的构造方法中访问父类的构造方法
2.调用普通方法
与调用构造方法一致,可以调用多个
3.调用变量
定义:super关键字可以调用父类的变量
必须要在子类的方法中调用
格式:
public void method2(String color){
System.out.println(super.color);
}
此时super.color输出的是父类中对color的定义
三、重写
方法的重写:发生在继承关系中,方法的名称一样,参数列表也一样
重写:override 方法的名称一样,参数的列表【也一样】。覆盖,覆写
重载:overload 方法的名称一样,参数列表【不一样】
注:1.父子类之间的方法名相同,参数列表相同
2.为了检测是否属于有效的重写。可以在重写的方法前写上@Override
3.子类重写的方法值返回类型<=父类方法的返回值类型
4.子类重写的方法的访问权限>=父类方法的访问权限
访问权限 public > protect > default(默认) > private
返回值:八大数据类型+void
对于“子类重写的方法值返回类型 <= 父类方法的返回值类型”:
作用一:保持代码的逻辑一致性。确保在多态环境中,通过父类引用调用子类重写的方法时,返回的值在类型上是可接受和可处理的,不会出现类型不兼容的错误。
作用二:增强代码的可扩展性。允许子类在返回值类型上进行一定的扩展和细化,以便在特定情况下提供更具体的返回信息,同时又不破坏父类已有的逻辑和使用方式。
对于“子类重写的方法的访问权限 >= 父类方法的访问权限”:
作用一:保障父类方法的可见性和可用性。确保父类中定义的具有一定访问权限的方法,在子类重写时不会被意外地限制访问,从而维持了整个继承体系中方法的可访问性和通用性。
作用二:符合封装原则。父类中具有较宽松访问权限的方法,通常是为了在继承体系中被合理使用和扩展,子类不应过度限制其访问,以保持代码的开放性和灵活性。
总的来说,这两条规则有助于维护面向对象编程中继承和多态机制的正确性、稳定性和可扩展性,使得代码更易于理解、维护和扩展。
二、object
定义:
Object类是所有类的父类,何一个类时候如果没有明确的继承一个父类的话,那么它就是Object的子类;
也可以做为最大的返回值类型
public Object method(){
return null;
}
重写例:
public String method(){
return null;
}
return null;语句用于从方法中返回空值。这意味着方法没有返回任何对象,即没有指向任何对象的引用
四、static关键字
static关键字的用法
一、修饰成员变量
1.如果static修饰了一个成员变量那么这个变量就叫类变量。
此时,这个变量就不再属于自己,而是属于当前所在的类。多个对象共享这个变量 一旦发生改变,所有对向对映的这个变量都会发生改变,调用时推荐直接使用类名.变量名
静态变量可以被本类中的所有方法调用
二、修饰成员方法
如果static修饰成员方法,这个成员方发就叫静态方法或者类方法。此时,他不在属于自己,而是属于当前类
格式:
public static void 方法名(){
方法体
}
1.静态的方法不能访问非静态的内容,因为内存里面是先有静态内容才有非静态内容的
2.静态方法里面不能有this关键字。因为this代表的某个对象。静态方法是类所有的
3.用类名访问静态成员变量或静态成员方法的时候,和对象无关,只和类有关
4.对于主类当中的静态方法可以省略类名来直接调用()
凡是用static来修饰的成员变量和成员方法都是类所有的,所有调用时推荐用类名来调用,不推荐用对象名来调用
静态方法可以用类名来调用,也可以通过对象名来调用
成员方法只能用对象名来调用
静态代码块:
格式:
public class 类名{
static{ 若干行代码: 静态代码块 }
}
特点:静态代码块只能使用一次,即当第一次用到本类时会执行
因为内存里先有的静态的内容,所以静态代码块优先于构造方法
在 Java 中,实例方法和类方法(也称为静态方法)主要有以下区别:
1. 调用方式:
● 实例方法需要通过创建类的实例对象来调用。
● 类方法可以直接通过类名调用,无需创建对象。
2. 访问权限:
● 实例方法可以访问实例变量和实例方法,也可以访问类变量和类方法。
● 类方法只能访问类变量和其他类方法,不能访问实例变量和实例方法。
3. 与对象的关联:
● 实例方法与特定的对象实例相关联,不同对象的实例方法可能操作不同的实例变量。
● 类方法不与特定的对象实例相关联,而是与整个类相关。
4. 内存分配:
● 实例方法在每个对象创建时都会分配独立的内存空间。
● 类方法在内存中只有一份,无论创建多少个对象。
五、抽象方法
一、定义:
抽象方法:不确定具体的实现细节的时候,就可以用抽象方法。
在方法前加上abstract关键字,去掉花括号,分号结束。不写方法体
抽象类:抽象方法所在的类必须是一个抽象类,即在class之前加上abstract
如何使用抽象类和抽象方法:
1.不能直接创建(new)抽象类和抽象方法
2.必须要有一个子类来继承此抽象父类
3.子类必须重写抽象父类中的抽象方法
重写:去掉abstract关键字,补上方法体{},写上方法体的内容(具体的实现细节)
4.创建子类对象来调用
二、格式:
抽象类:
public abstract class Animal {
}
抽象方法:
public abstract void eat();
三、特点:
1.和普通类比abstract类中可以有abstract方法。也可以没有 但是abstract方法所在的类必须是abstract类
2.对于abstract类,不能使用new运算符创建该类的对象,只能产生其子类,由子类创建对象 3.如果一个非abstract类是abstract的子类,他必须具体实现父类的所有的abstract方法, 重写的时候去掉abstract关键字,给出具体的方法体
4.如果一个abstract类是abstract类的子类,那么他可以重写父类的abstract方法,也可以继承父类的abstract方法
5.对于abstract方法,不允许使用final修饰abstract方法,也不允许使用static和private修饰abstract方法
6.抽象类无法实例化,需要借用子类,来调用属性和方法
抽象方法重写时,权限修饰符与返回值尽量保持一致
六、多态
多态:一种事物的多种表现形式
JAVA:父类的某个方法被子类重写时产生的各自的功能行为(形态)
代码体现:父类引用指向子类对象(左父右子,等号的左边是父类引用,右边是子类对象)
子类对象就是被当做是父类来使用
格式:父类名 对象名 = new 子类名();
总结:
多态里面的成员变量访问:编译看左边,运行也看左边
多态里面的成员方法访问:编译看左边,运行看右边
二、格式
创建对象:
//Fu OBJ = new Fu();
Fu obj = new Zi();
调用方法:
obj.method();//子类
由于多态中的成员方法访问是编译看左运行看右
所以在编译时,会先找到父类中的method方法,确认是有这个方法之后,在去运行子类中的method方法,如果父类中没有method方法,那么程序将会报错
子类可以没有这个方法,但是父类必须得有
调用变量:
System.out.println(obj.num);
通过,子类来调用变量
由于多态中的变量访问是编译看左边,运行也看左边
所以在编译时,会先找到父类中的变量,运行时,也是在调用父类的变量
子类可以没有,但是父类必须有
七、在继承关系中的问题
1.父类与子类的成员变量重名
都是优先使用调用者的变量和方法,没有就向上找
直接通过子类对象访问成员变量:优先子类内容,没有就向上找
间接通过成员方法访问成员变量:方法属于谁就优先用谁,没有就向上找 System.out.println(zi.abc); //找不到就报错
2.父类对象只能访问父类里的属性和方法,不能访问子类里独有的属性和方法
子类对象既能访问父类里的对象和方法又能访问子类中独有的属性和方法
八、final关键字
Final关键字的几种用法
1.修饰方法:使其不能被覆盖重写
public final void speak(){}
2.修饰类:不能被继承,不能有子类。(很少使用)
public final class A{}
3.修饰成员变量:需赋值,且不可改变--常量。
final double a = 2.14;
九、接口
定义:
在Java中是一种引用的数据类型,里面最主要的内容就是抽象方法
格式:
public interface 接口名{
//接口内容
}
常见内容:
1.常量
(Java7及以上的版本支持)
格式:
【public】 【static】 【final】 数据类型 变量名 = 数据值;
(1)接口中的变量必须赋初值
(2)常量使用时尽量全部使用大写,多个单词_分割
2.抽象方法
(Java7及以上的版本支持)
格式:
【public】 【abstract】 返回值类型 方法名(参数);
接口中只有抽象方法
(1)接口中的抽象方法修饰符必须是用public abstract来修饰
(2)方法的三要素可以随意定义,只要符合规范即可
使用:
(1.)接口中的抽象方法要想使用,必须要有一个类来实现(implements)接口
因为接口不能直接创建对象来使用
(2)接口的实现类必须重写(去掉abstract关键字,加上{}和方法体)接口中所有的抽象方法
格式:
public class 实现类 implements 接口名
{ * //重写接口中的所有抽象方法 * }
若实现类没有重写任意的抽象方法,那这个实现类必须定义为抽象类
(3)主类中创建实现类的对象进行使用
(实现类最重要的一个目的:就是为了创建对象来使用接口中的各种方法)
3.默认方法
(Java8及以上的版本支持)
格式:
【public】 default 返回值类型 方法名(){ * 方法体 * }
(1)默认方法若不重写,会被接口的实现类对象直接调用(默认方法也会被实现类所拥有) * (2)默认方法若在实现类里重写,那么实现类的对象在调用这个默认方法时,调用的就是重写后的默认方法
4.静态方法
(Java8及以上的版本支持)
【public】 static 返回值类型 方法名(参数名){方法体};
注意:不能通过实现类的对象调用接口中的静态方法,要想调用只能使用接口名来调用
静态方法不能被重写。
原因如下: 静态方法与对象无关,只与声明的类/接口有关
重写:为了实现多态,通过对象来调用重写的方法从而产生不同的行为状态。而类不能直接调用重写的方法
5.private方法
(Java9及以上的版本支持)
把某个方法限制在只有当前接口中可以使用,在实现类里不可用
格式:
(1)普通私有方法
private 返回值类型 方法名 (参数){方法体}
(2)静态私有方法
private static 返回值类型 方法名 参数名(参数){方法体}
(1)接口回调:接口声明一个变量:里面存放的是该接口的实现类的对象的引用
接口名 变量sm = new 实现类名1();
sm.抽象方法();
接口回调 接口名 变量sm = new 实现类名2();
sm.抽象方法(); //接口回调
会有不同的表现形式----多态
分别是两个实现类在实现接口的时候给出的抽象方法不同的具体的行为
十、内部类
一、定义:
一个类里面又包含了一个类,那么这个里面的类叫内部类,外边的类叫外嵌类
格式:(作为一种成员变量)
【public】 class 外部类名{
//成员变量
//成员方法
public class 内部类名{
//成员变量
//成员方法
}
}
使用规则:
内用外:随便用
外用内:借助内部类的对象
1.在外部类的方法当中,创建一个内部类的对象,由该对象来调用,最后在主类中调用外部类的方法
2.在主类中直接使用内部类的内容:
外部类.内部类 对象名 = new 外部类().new 内部类();
注意:
1.内部类的类体中不可以声明类变量和类方法(static)
2.外部类的类体中可以声明类变量和类方法
内部类可以被修饰为static,外部类不可以被修饰为static
3.编译时外部类产生正常的.class文件,内部类也产生.class文件
格式为
外部类$内部类.class
成员变量重名时的访问规则:
例子:
public class Out {
int num = 10; //外部类的成员变量
public class In{
int num = 20; //内部类的成员变量
public void methodIn(){
int num = 30; //内部类的局部变量
System.out.println(num); //就近原则,内部类局部变量
System.out.println(this.num); //内部类的成员变量
System.out.println(Out.this.num); //外部类的成员变量
}
}
}
1.外部类的成员变量
外部类名.this.重名的成员变量
2.内部的成员变量
this.重名的成员变量
(this是相对的,要看清除它用时所在的类是哪一个)
内部类的局部变量
直接使用重名的成员变量(就近原则)
十一、异常
在程序运行时一般会发生两种错误
1.编译错误:一般语法错误,如果不修改就无法运行
2.运行错误:程序看起来没有问题,也没有标红报错,但是在运行时会发生异常:数组索引越界异常
处理异常:
try{
捕捉异常:可能发生的异常语句放进来:
}
catch(异常类 异常类的声明对象){
发生异常后你想怎么处理
}
finally{ //程序的结束语,可以省略
无论是否发生异常都必须执行的语句
}
例子:
public class Test {
public static void main(String[] args) {
int x = 2;
int i = 0;
System.out.println(i/x);
try{
System.out.println(x/i);
}
catch (ArithmeticException a){ //运行时抛出异常的类名,一般有两种
//一种是jdk已经定义好的异常类,它是Exception的子类
//另一种可以自己定义一个异常类,但要让这个异常类继承Exception类
//Exception类中有一种方法:getMessage(),用来获得异常提示
System.out.println("发生异常:"+a.getMessage());
}
finally { //可以省略
System.out.println("程序运行完毕");
}
}
}