java基础---类和对象(4)
一、 static关键字
使用static关键字修饰成员变量表示静态的含义,此时成员变量由对象层级提升为类层级,整个类共享一份静态成员变量,该成员变量随着类的加载准备就绪,与是否创建对象无关
- 使用static修饰属性:静态变量(或类变量)
- 静态变量随着类的加载而加载,可以通过类名.静态变量的方式进行调用
- 静态变量的加载早于对象的创建
- 类只会加载一次,静态变量在内存中只有一份,在方法区的静态域中
- 使用static关键字修饰类方法:静态方法
- 静态方法中只能代用静态方法的属性或方法
- 非静态方法中,可以调用非静态的方法和属性,也可以调用静态的方法和属性
- 特点:
- 在Java类中, 可用static修饰属性、 方法、 代码块、 内部类,不能修饰构造器
- 被static修饰的成员随着类的加载而加载,优先于对象存在,被所有对象共享
- 可以直接被类调用,通过类名.静态成员变量或方法的方式
- 注意事项:
- 在非静态成员方法中既能访问非静态成员,又能访问静态成员 (成员:成员变量 + 成员方法, 静态成员被所有对象共享)
- 静态成员方法中职能访问静态成员,不能访问非静态成员(成员:成员变量 + 成员方法, 因为此时可能还没有创建对象)
- 隶属于类层级并被所有对象共享的才可使用static关键字修饰
- 在静态的方法内,不能使用this关键字、super关键字
- static修饰的方法不能被重写
- 内存解析

二、代码块
代码块用于初始化类和对象,只能用static修饰,分为静态代码块和非静态代码块
- 静态代码块
- 内部可以有输出语句,随着类的加载而执行,只执行一次,初始化类的信息
- 不可以对非静态的属性初始化,不可以调用非静态的属性和方法
- 如果一个类中定义了多个静态代码块,按照声明的先后顺序执行
- 静态代码块的执行优先于非静态代码块的执行
- 静态代码块只能调用静态的属性和静态方法,不能调用非静态的结构
- 非静态代码块
- 内部可以有输出语句
- 随着对象的创建而执行
- 每创建一个对象就会执行一次非静态代码块,可以在创建对象
- 如果一个类中定义了多个非静态代码块,按照声明的顺序先后执行
- 非静态代码块可以调用静态的属性和方法或者非静态的属性和方法
-
对属性可以赋值的位置:
①默认初始化-->②显式初始化/⑤在代码块中赋值(同级别下按先后顺序执行 )-->③构造器中初始化-->④有了对象以后,可以通过"对象.属性"或"对象.方法"的方式,进行赋值
package com.atguigu.java3; class Root{ static{ System.out.println("Root的静态初始化块"); } { System.out.println("Root的普通初始化块"); } public Root(){ super(); System.out.println("Root的无参数的构造器"); } } class Mid extends Root{ static{ System.out.println("Mid的静态初始化块"); } { System.out.println("Mid的普通初始化块"); } public Mid(){ super(); System.out.println("Mid的无参数的构造器"); } public Mid(String msg){ //通过this调用同一类中重载的构造器 this(); System.out.println("Mid的带参数构造器,其参数值:" + msg); } } class Leaf extends Mid{ static{ System.out.println("Leaf的静态初始化块"); } { System.out.println("Leaf的普通初始化块"); } public Leaf(){ //通过super调用父类中有一个字符串参数的构造器 super("mid"); System.out.println("Leaf的构造器"); } } public class LeafTest{ public static void main(String[] args){ new Leaf(); System.out.println(); new Leaf(); } } //执行结果 /* Root的静态初始化块 Mid的静态初始化块 Leaf的静态初始化块 Root的普通初始化块 Root的无参数的构造器 Mid的普通初始化块 Mid的无参数的构造器 Mid的带参数构造器,其参数值: mid Leaf的普通初始化块 Leaf的构造器
Root的普通初始化块
Root的无参数的构造器
Mid的普通初始化块
Mid的无参数的构造器
Mid的带参数构造器,其参数值:mid
Leaf的普通初始化块
Leaf的构造器 */
三、final关键字
final可以用于修饰类、方法和变量,意为最终的,不可变的
- final 用来修饰一个类:此类不能被其他类所继承。
- final 用来修饰方法:表明此方法不可以被重写
- final 用来修饰变量:此时的"变量"就称为是一个常量,可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化
- final修饰局部变量,表明形参是一个常量,一旦赋值不能在进行重新赋值
- static final 用来修饰属性:全局常量
public class FinalTest { final int WIDTH = 0; final int LEFT; final int RIGHT; // final int DOWN; { LEFT = 1; } public FinalTest(){ RIGHT = 2; } public FinalTest(int n){ RIGHT = n; } public void setDown(int down){ // this.DOWN = down; //在方法体不可以对final属性进行赋值操作 } public void doWidth(){ // width = 20;//在方法体不可以对final属性进行赋值操作 } public void show(){ final int NUM = 10;//常量 // NUM += 20; //final局部变量一旦初始化不可以在被复制 } public void show(final int num){ // num = 20;//final 局部变量一旦被实参传入,就已经赋值,不能重新赋值,编译不通过 System.out.println(num); } public static void main(String[] args) { int num = 10; num = num + 5; //局部变量可以重复赋值 FinalTest test = new FinalTest(); // test.setDown(3); test.show(10); } } final class FinalA{ } //class B extends FinalA{ // //} //class C extends String{ // //} class AA{ public final void show(){ } } class BB extends AA { /*public void show(){ //final方法不可以被重写 }*/ } final class Root{} // class sub extends Root{} // final 类不可以被继承
四、abstract关键字
abstract用于修饰抽象的类或方法,抽象类使用extends实现
- 抽象类: 指不能具体实例化的类并且使用abstract关键字修饰,也就是不能创建对象
- 抽象类中一定有构造器,便于子类实例化时调用,但是抽象类不能调用自身构造器实例化
- 多态的一种表现形式:抽象类的子类实例化形成抽象类
- 抽象类中可以有成员变量、构造方法、成员方法
- 抽象类中可以没有抽象方法,也可以有抽象方法
- 当一个类继承抽象类后必须重写抽象方法,否则该类也变成抽象类,也就是抽象类对子类具有强制性和规范性,因此叫做模板设计模式
- 抽象方法:抽象方法用abstract修饰方法,没有方法体
- 包含抽象方法的一定是抽象类,抽象类可以没有抽象方法
- 若子类重写了父类的所有抽象方法后,子类可以实例化
- 若子类没有全部重写父类中的所有抽象方法,该子类也是一个抽象类,需要适用abstract修饰
- abstract不能用来修饰私有方法、静态方法、final的方法、final的类
五、接口
接口使用interface定义,使用implements实现
- JDK7以前,接口里只能定义全局变量和抽象方法,(public static final )+ 常量; public abstract+ 方法
- JDK8以后,接口可定义静态方法和默认方法,只能通过接口直接调用静态方法,可以通过类的对象调用默认方法,如果重写了接口中的默认方法,就会被覆盖
- 继承关系大于接口实现关系
interface Playable { void play(); } interface Bounceable { void play(); } interface Rollable extends Playable, Bounceable { Ball ball = new Ball("PingPang"); } class Ball implements Rollable { private String name; public String getName() { return name; } public Ball(String name) { this.name = name; } public void play() { ball = new Ball("Football"); System.out.println(ball.getName()); } }
- 接口不可以定义构造器,没有默认构造器,不能实例化
- 如果实现类覆盖了接口中的所有抽象方法,该实现类可以被实例化,否则该实现类是一个抽象类
- 接口和接口之间可以多继承,实现类和接口之间可以多实现
- 接口主要用于代理模式,为其他对象提供一种代理以控制对这个对象的访问。
- 接口可以用于工厂模式

若一个接口中定义了一个默认方法,而另外一个接口中也定义了一个同名同参数的方法,在实现类同时实现了这俩个接口时会出现接口冲突
class Man implements Filial, Spoony { @Override public void help() { System.out.println("我该怎么办呢?"); Filial.super.help(); Spoony.super.help(); } } interface Filial {// 孝顺的 default void help() { System.out.println("老妈,我来救你了"); } } interface Spoony {// 痴情的 default void help() { System.out.println("媳妇,别怕,我来了"); } }
若一个接口中定义了一个默认方法,而父类中也定义了一个同名同参数的非抽象方法,由于类优先原则,不会出现冲突问题,接口中的同名同参数默认方法会被忽略
七、内部类
一个类的定义位于另一个类的内部称为内部类 ,Inner class一般用在定义它的类或语句块之内,在外部引用它时必须给出完郑的名称,且内部类不能与他所在的外部类同名
- 类中的内容:成员变量、成员方法、构造方法、静态成员、构造块和静态代码块、内部类。
- 当一个类存在的价值仅仅是为某一个类单独服务时,那么就可以将这个类定义为所服务类中的内部类,这样可以隐藏该类的实现细节并且可以方便的访问外部类的私有成员而不再需要提供公有的get和set方法
-
分类:
-
普通内部类 - 直接将一个类的定义放在另外一个类的类体中。
-
普通内部类和普通类一样可以定义成员变量、成员方法以及构造方法等。
-
普通内部类和普通类一样可以使用final或者abstract关键字修饰。
-
普通内部类还可以使用private或protected关键字进行修饰。
-
普通内部类需要使用外部类对象来创建对象
- 如果内部类访问外部类中与本类内部同名的成员变量或方法时,需要使用this关键字
-
-
访问修饰符 class 外部类的类名 { 访问修饰符 class 内部类的类名 { 内部类的类体; }
-
-
静态内部类 - 使用static关键字修饰的内部类,隶属于类层级
-
静态内部类不能直接访问外部类的非静态成员。静态内部类可以直接创建对象。
-
如果静态内部类访问外部类中与本类内同名的成员变量或方法时,需要使用类名.的方式访问。
-
-
访问修饰符 class 外部类的类名 { 访问修饰符 static class 内部类的类名 { 内部类的类体; } }
-
-
局部内部类 - 直接将一个类的定义放在方法体的内部时
-
局部内部类只能在该方法的内部可以使用。
-
局部内部类可以在方法体内部直接创建对象。
-
局部内部类不能使用访问控制符和static关键字修饰符。
-
局部内部类可以使用外部方法的局部变量,但是必须是final的,因为局部内部类和局部变量的声明周期不同所致
-
-
访问修饰符 class 外部类的类名 { 访问修饰符 返回值类型 成员方法名(形参列表) { class 内部类的类名 { 内部类的类体; } } }
-
- 匿名内部类 - 就是指没有名字的内部类
接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 };
浙公网安备 33010602011771号