一、static静态成员、静态代码块、静态导入
static(静态成员:静态变量、静态方法):
package com.oop.demo07;
/*
被static修饰的成员均为静态成员。静态成员均属于类,而非对象。
静态成员和类一起加载(JVM加载class文件时)初始化,存储在堆中的方法区。
生命周期与类相同,从类加载到JVM卸载。
*/
// static :
public class Student {
private static int age; // 静态变量(类变量)。属于类而非对象,所有实例共享同一个静态变量。在类加载时初始化,内存中只有一份拷贝。常用于共享数据或常量。
private double score; // 实例变量--对象级别。每个对象独立拥有。
public void run(){
go();
}
public static void go(){ // 静态方法: 只能访问静态成员(变量、方法)。不能使用this或super关键字。
}
public static void main(String[] args) {
Student s1 = new Student();
System.out.println(Student.age); // 0。对于static静态变量,建议使用类名访问
System.out.println(new Student().age); // 不推荐用对象访问静态变量
System.out.println(s1.age); // 0
System.out.println(s1.score); // 0.0
new Student().run(); // 创建匿名对象并调用方法。 对象.方法。
Student.go(); // 静态方法推荐用类名调用
go(); // 在同一个类中可以直接调用。静态成员【也叫静态属性】(包括静态变量、静态方法)可直接调用。
}
}
匿名代码块、静态代码块:
package com.oop.demo07;
public class Person {
{
// 匿名代码块(实例初始化块): 用于对象初始化,可替代多个构造方法的公共代码。
System.out.println("匿名代码块"); // 2. 每次创建对象时都会(自动)执行,在构造方法之前执行。可以有多个,按定义顺序执行。
}
static { // 静态代码块: 用于初始化静态资源(如加载配置文件、静态变量)
System.out.println("静态代码块"); // 1. 静态代码块在类加载时执行,且只执行一次。执行顺序优先于任何其他代码块和构造方法。
}
public Person() {
System.out.println("构造方法"); // 3.
}
public static void main(String[] args) {
System.out.println("============================================="); // 这一句上面还会调用并输出静态代码块,因为它是和类一起加载的。
Person person1 = new Person(); // 输出: 匿名代码块 构造方法
System.out.println("=============================================");
Person person2 = new Person(); // 输出: 匿名代码块 构造方法
}
}
static静态导入:
package com.oop.demo07;
import static java.lang.Math.*; // 静态导入Math类的所有静态成员。
import static java.lang.Math.random; // 静态导入方法。导入java.lang包下的Math数学工具类中的random方法。可在调用该方法时无需带类名直接调用。
import static java.lang.Math.PI; // 静态导入常量
public final class Test { // 通过final修饰的类不能被继承,也就不会有子类。
public static void main(String[] args) {
System.out.println(Math.random()); // Math.random() : 生成[0.0,1.0)之间double类型的随机数
System.out.println(random()); // 等价于上面的调用。
System.out.println(PI);
System.out.println(Math.PI); // PI -- double类型的圆周率常量
}
}
二、abstract抽象类、抽象方法
抽象类、抽象方法:
package com.oop.demo08;
// abstract : 定义抽象类和抽象方法的关键字。
public abstract class Action { // 被abstract修饰的类不能实例化(不能被new),可以包含抽象方法和具体方法。主要用于继承。
public abstract void doSometing(); // 抽象方法 : 只有声明没有实现,子类必须实现(除非子类也是抽象类)。
/* 抽象类的约束:
对子类的强制要求(必须实现所有抽象方法)。
对抽象类的使用限制(不能直接实例化)。
对代码结构的规范。
*/
/* 抽象类的意义:
提取多个类的共性。抽象类用于定义共性行为模板。
子类可实现差异化行为,需要定义一些公共方法但又希望部分方法由子类决定时。
作为框架的基础类。
实现多态基础。
*/
// 知识小点: 抽象类不可以被new创建对象,实例化。但是可以有构造器,子类实例化时会调用父类(抽象类)的构造器。
}
(实现抽象类的)子类:
package com.oop.demo08;
// 抽象类中的方法,由继承它的子类来实现其所有抽象方法。除非该子类也是一个抽象类,那么由具体子类去实现。
public class A extends Action{ //
@Override // 重写
public void doSometing() {
}
}
三、interface接口、implements实现
如图:
UserService(接口):
package com.oop.demo09;
// 接口定义关键字: interface。 接口都需要有实现类
public interface UserService { // 一般在接口中定义方法然后通过约束(实现类)来实现它。
public static final int AGE = 99; // 接口中的属性,默认为 public static final 【公共静态常量】(一般不建议在接口中定义常量)
public abstract void run(String name); // 接口中的方法声明,类型默认为 public abstract。接口方法默认是抽象的(abstract)。
void run1(String name);
void add();
void delete();
void update();
void query();
}
TimeService(接口):
package com.oop.demo09;
public interface TimeService {
void timer();
}
UserServiceImpl(实现接口)类:
package com.oop.demo09;
// 抽象类 : extends--单继承
/* 接口实现类:
1. 使用 implements(实现) 关键字来实现接口
2. 必须(重写)实现所有接口方法(除非自身是抽象类)
3. 可以实现多个接口(伪多继承)
4. 命名规范: 实现类通常以Impl结尾
*/
public class UserServiceImpl implements UserService,TimeService{
@Override
public void run(String name) {
}
@Override
public void run1(String name) {
}
@Override
public void add() {
}
@Override
public void delete() {
}
@Override
public void update() {
}
@Override
public void query() {
}
@Override
public void timer() {
}
}
JDK8后接口中的默认方法、静态方法:
package com.oop.demo09;
public interface ModernInterface { // JDK8以后,接口中可以有默认方法和静态方法。
void abstractMethod(); // 1. 抽象方法(接口方法),隐式默认为 public abstract 类型。子类必须实现。
// 2. 默认方法(Java 8+)。用default修饰,子类可直接继承或重写。作用:解决接口新增方法时的向后兼容问题。在不破坏现有代码的前提下,扩展接口功能。
default void defaultMethod() {
System.out.println("默认方法");
// privateMethod(); // 调用私有方法
}
// 3. 静态方法(Java 8+)。用static修饰,(子类)可直接通过接口名调用。目的: 提供工具方法,避免额外的工具类。
static void staticMethod() {
System.out.println("静态方法");
}
// 4. 私有方法(Java 9+)。用private修饰,仅在接口内部被默认方法或静态方法调用。目的: 提取接口中重复的代码逻辑(代码复用),提高内聚性。
// private void privateMethod() {
// System.out.println("私有方法");
// }
}
抽象类与接口不同的关键点:
抽象类 | 接口 | |
---|---|---|
构造方法 | 有 | 无 |
设计理念 | “是什么”(is–关系) | “能做什么”(has–a / can–do关系) |
使用场景 | 提取多个相关类的共性 | 定义不相关类共有的行为 |
接口定义行为,抽象类共享代码。
接口作用:实现多态和解耦。
四、内部类
如图:
非静态内部类、静态内部类、局部内部类:
package com.oop.demo10;
public class Outer {
private int id = 10; // 外部类私有属性
public void out(){
System.out.println("这是外部类的方法");
}
/*
成员内部类(非静态内部类):
1. 可以访问外部类的所有成员(包括private私有成员)
2. 不能有静态成员(除非是final常量)
3. 必须先有外部类实例才能创建内部类实例
*/
public class Inner{ // 成员内部类
public void in(){
System.out.println("这是内部类的方法");
}
public void getID(){
System.out.println(id);
// 内部类中访问外部类实例的两种方式:
System.out.println("外部类引用方式1: " + Outer.this.id); // 成员内部类隐式持有外部类实例的引用(即Outer.this机制):
System.out.println("外部类引用方式2: " + Outer.this); // 当创建成员内部类实例时,它自动持有创建它的外部类实例的引用。Outer.this:java的特殊语法,表示:当前内部类关联的外部类实例
}
/*
静态内部类
1. 不依赖外部类实例,可以直接创建
2. 不能直接访问外部类的非静态成员
3. 可以有静态和非静态成员
*/
}public static class Inner1{ // 静态内部类: 静态内部类不会持有外部类实例的引用
public void in(){
System.out.println("这是静态内部类的方法");
}
}
/*
局部内部类(方法内部类)
1. 定义在方法或作用域内
2. 只能在该方法或作用域内使用
3. 该类不能有访问修饰符(public/private等)
4. 可以访问外部类所有成员,但只能访问所在方法中的final或有效final局部变(即该方法中初始化后不再修改的局部变量)
*/
public void method(){
final String localVar = "局部变量";
class Inner{ // 局部内部类,和局部变量差不多,外部无法访问
public void in(){
System.out.println("访问外部类私有id: " + id);
System.out.println("访问局部变量: " + localVar); // 只能访问所在方法中的final或有效final的局部变量
}
}
// 在方法内部使用局部内部类
Inner inner = new Inner();
inner.in();
}
}
class A{
public static void main(String[] args) { // 同一个文件中的其他类(不是内部类)。java文件中允许有多个类,但只能有一个public类。
}
}
匿名内部类:
package com.oop.demo10;
/*
匿名内部类是没有名字的内部类,它同时完成类的定义和实例化。
通常用于只需要使用一次的类实现,比如事件监听器、线程创建等场景。
可以是实现接口或继承父类的形式。
*/
public class Test {
public static void main(String[] args) {
// 创建一个Apple对象并立即调用其eat方法,但不保留对象引用
new Apple().eat(); // 1. 匿名对象的创建和使用
// 2. 匿名内部类的使用(接口实现)
// 直接创建并实现UserService接口,不定义具体类名。适合一次性使用。
new UserService(){ // 匿名内部类: 匿名内部类会隐式持有外部类的引用(如果是非静态上下文)
@Override
public void hello() {
System.out.println("hello");
}
};
// 3. 将匿名内部类赋值给接口变量
// 这种形式允许我们后续通过变量名调用匿名内部类的方法,适合多次调用。
UserService userService = new UserService(){ // 也是匿名内部类
@Override
public void hello() {
System.out.println("Hello");
}
};
userService.hello(); // 调用匿名内部类的方法
}
}
class Apple{
public void eat(){
System.out.println("eat");
}
}
interface UserService{
void hello();
}
成员内部类(非静态内部类)的创建:
package com.oop.demo10;
public class Application {
public static void main(String[] args) {
// 成员内部类的使用:
Outer outer = new Outer(); // 1、必须先创建外部类实例
// 通过外部类来实例化内部类
Outer.Inner inner = outer.new Inner(); // 2、成员内部类的声明创建。创建的Inner实例会自动持有outer的引用(即Outer.this)。
inner.in();
inner.getID();
Outer.Inner1 inner1 = new Outer.Inner1(); // 静态内部类不需要外部类实例,可直接创建
inner1.in();
outer.method(); // 方法内部会创建和使用局部内部类
}
}