java篇 类的进阶0x0D:接口与抽象类

文章详细介绍了Java接口的特性,包括接口的内容构成(抽象方法和静态常量)、抽象方法的默认实现、私有方法和静态方法的引入,以及多态和IDEA的快捷实现接口功能。此外,讨论了接口与抽象类的区别,强调接口主要用于定义规范,而抽象类可以包含非公有的成员和方法。文章还探讨了接口继承的冲突处理和如何避免抽象方法的默认实现冲突。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

接口

定位

接口的本质是一种特殊的类,特殊在于接口仅仅是为了提供一种规范/标准。

内容构成

接口由一堆抽象方法(public abstract)和静态常量(public static final)组成。

// 接口1定义示例
public interface Expired{
	// 接口中的抽象方法(省略 public abstract)
	void sayHi();

	// 定义静态常量(省略 public static final)
	int expiredays = 365;                          
}

// 接口2定义实例
public interface VirtualGoods {
}

// 实现接口
public class Product implements Expired,VirtualGoods{

}

// 调用类
public class TestUse{
	public static void main(String[] args){
		Expired exp = new Product();
	}
}

抽象方法

接口里的方法(全都是抽象方法)都是 public abstract 修饰的,方法有名字、参数和返回值,但没有方法体,以分号结束。

因为接口里的方法都是(且只能)用 public abstract 修饰,所以这两个修饰符可以省略不写。

接口实际上是定义“标准”或者说“规范”(有哪些方法、方法签名、方法返回值类型),但不定义具体如何实现这些标准(方法体)。

由于方法没有方法体,所以建议给方法写好注释,说明定义这个方法的目的。

缺省实现的抽象方法

java 8 中,接口中开始允许有缺省实现的抽象方法。即可以在抽象方法中定义方法体,如果子类没有实现这个抽象方法,则以这个事先定义的“缺省”方法体作为这个抽象方法在子类中的具体实现。如果子类中对这个抽象方法进行了实现(覆盖),则无论抽象方法是否定义了“缺省”方法体,都以子类实现(覆盖)的方法体为准,作为具体实现。

// 接口中的抽象方法
void sayHi();

// 等同于下面写法(也就是说 public abstract 可写可不写)
public abstract void sayHi();

// 但如果定义缺省实现的抽象方法,就不能再写 abstract 了,语法是如下:
default void sayHi(){
    xxxx;
}

// 或写成:
public default void sayHi(){
    xxxx;
}

// 测试下方代码写法也正常运行:
default public void sayHi(){
    xxxx;
}

// 但如果同时出现 default 和 abstract 那么无论怎么排列组合都会报错:java: 非法的修饰符组合: abstract和default
// public abstract default
// public default abstract
// default public abstract

// 即,只要有 abstract 修饰,就不能有方法体。default 与 abstract 在接口中是无法同时出现的。

Kevin:我觉得这个 default 定义的所谓“抽象方法的缺省实现”,已经不能算是抽象方法了,它就仅仅是一个普通方法而已,看子类继承的时候要不要覆盖。

private 方法

java 9 中,接口中开始允许有 private 方法,当然这个 private 方法自然是只能服务于抽象方法的缺省实现了,否则也没有地方能用得上(若用在接口中的静态方法中显然也是不行的,因为静态方法中不允许调用非静态的方法,否则报错)。本质上,private 方法只是把抽象方法的缺省实现代码块中可以复用的一部分逻辑抽取出来而已。使用 private 方法是语法上允许了,但实际上真的不建议把接口中抽象方法的缺省实现搞得这么复杂。

优化代码

多说一句:其实实际上 java 在运行期间优化代码的时候,很多时候就是把 private 方法的代码拷贝/插入到调用这个 private 方法的地方,以减少一次方法的调用。(很多语言都是这样优化的)

静态方法

java 9 中,接口中还开始允许有静态方法(static)。静态方法可以被接口中的 public、private 方法调用,也可以在调用类中通过 接口名.静态方法名(参数列表) 调用,但在调用类中不能使用 实现了接口的子类的实例名.静态方法名(参数列表) 调用,(甚至不能用实现了接口的子类名.静态方法名(参数列表) 调用)否则会报错。这一点和普通类中的静态方法有明显区别。

另外,接口中的静态方法的访问修饰符只能是 public (可以省略不写,java 会默认是 public 的),不能定义为 protected、private 等其他的。

// 接口1
public interface Expired {

	// 抽象方法的缺省(默认)实现
    default boolean isDamaged() {
        boolean isDamaged = !qualityCondition();
        // describe();       // 可以在缺省实现方法体中调用 static 方法,正常执行。
        return isDamaged;
    }

	// private 方法
    private boolean qualityCondition() {
        // describe();       // 可以在 private 方法体中调用 static 方法,正常执行。
        return Math.random() < 0.5;
    }

    // 静态方法
    // 其实下方的静态方法也能写成 public static void describe(){ 但 IDEA 会提示 public 是多余的
    static void describe(){
        System.out.println("This is a method from Expired.");
    }

}
// 接口2
public interface VirtualGoods {
}


// 实现接口的类
public class Product implements Expired,VirtualGoods {	// 因为接口的抽象方法有默认实现,所以可以选择不覆盖此抽象方法
}

// 调用类
public class TestUse {
    public static void main(String[] args) {
        Expired exp = new Product();
        System.out.println("当前商品损坏情况: " + exp.isDamaged());     // 当前商品损坏情况: true
		// exp.describe(); // 报错:java: 静态接口方法调用非法,应将接收方表达式替换为类型限定符 'org.test.interfacetest.Expired'
        Expired.describe();     // This is a method from Expired.
        // Product.describe();		// 报错。Product 类中找不到 describe 方法。IDEA 建议替换成 Expired 来调用。
    }
}

由于很多公司仍旧沿用 java 8,因此在设计时,尽量还是别在接口中定义 private 方法以及静态方法。

静态常量

接口里不能定义成员变量,定义的变量默认(且必须)都是 public static final 的(静态常量),这三个修饰符同样可以省略。

并且本身接口就不能实例化,定义成员变量也白搭,所以也没有这个需求。

// 接口的定义示例:

/**
 * 这是一个过期商品的接口,可以检测这个商品是否在卖,大概还能在架上多少天
 */
public interface Expired {
    /**
     * 返回当前在架情况
     *
     * @return 是否在架
     */
    boolean isOnSale();                  // 定义抽象方法

    /**
     * 根据过期时间计算还能在商品货架上放多少天
     *
     * @param day   过期前剩余天数
     * @return      大概能再放多少天
     */
    int saledays(int day);              // 定义抽象方法

    /**
     * 返回出厂设定的过期时间
     */
    public abstract void expireday();       // 不会报错,但 IDEA 会提示建议你删除多余的 public abstract 修饰符


    public static final String brand = "Big Rabbit";      // 定义静态常量
    int expiredays = 365;                          // 定义静态常量(省略 public static final)

}


// 再定义一个完全没有任何抽象方法和静态常量的接口
public interface VirtualGoods {
}

在一个项目里,如果需要一大堆的常量定义,并打算将这些常量放到一个单独的文件里时,可以考虑使用 interface 接口文件,而非 class 公共类文件来定义。这样就不用在每个常量前写 public static final 了,因为 interface 里的变量都是静态常量。使用时只需要 import static 把接口中的常量 import 进来即可。

应用特点

接口可以让一个类有多种类型,类似于多继承。即一个类可以同时 implements 多个接口。

接口无法被实例化。

// 接口的应用示例:
// 定义一个类来实现接口(需要覆盖接口中的所有抽象方法写出方法体,只要有抽象方法未被覆盖实现,都会报错)
public class Product implements Expired,VirtualGoods {

    @Override
    public boolean isOnSale() {
        return true;
    }

    @Override
    public int saledays(int day) {
        return (int)(day * 0.95);
    }

    @Override
    public void expireday() {
        System.out.println("Total :"+expiredays);
    }
}


// 调用类
public class TestUse {
    public static void main(String[] args) {
        Product candy = new Product();
        System.out.println(candy.isOnSale());           // true
        System.out.println(candy.saledays(200));        // 190
        candy.expireday();                              // Total :365
        System.out.println(candy.expiredays);           // 365
        System.out.println(Product.expiredays);         // 365
        System.out.println(Expired.expiredays);         // 365
        System.out.println(candy.brand);                // Big Rabbit
        System.out.println(Product.brand);              // Big Rabbit
        System.out.println(Expired.brand);              // Big Rabbit
    }
}

注意在什么情况下使用接口。就比如说这个例子中,商品是否过期,可以作为一个接口被商品所实现。但如果说你定义的接口是 Animal(动物),再用 People(人类)去实现这个接口就很奇怪了,因为 Animal 和 People 更合理的是设计成一个类继承关系,而不是接口实现的方式。

多态

接口虽然不能实例化,但是可以用实现接口的类的引用/实例,给接口的引用赋值。类似于可以使用子类的引用/实例给父类引用赋值。

与类继承中存在的方法覆盖导致的多态一样,实现接口的不同类也会表现出这种多态现象。

因为毕竟接口本质上就是一种特殊的类,“实现某个接口”,其实和“继承某个类” 本质上没太大区别。

// 接口 1
public interface Expired {
    /**
     * 返回当前在架情况
     *
     * @return 是否在架
     */
    boolean isOnSale();                  // 定义抽象方法

    /**
     * 根据过期时间计算还能在商品货架上放多少天
     *
     * @param day   过期前剩余天数
     * @return      大概能再放多少天
     */
    int saledays(int day);              // 定义抽象方法

    /**
     * 返回出厂设定的过期时间
     */
    public abstract void expireday();       // 不会报错,但 IDEA 会提示建议你删除多余的 public abstract 修饰符


    public static final String brand = "Big Rabbit";      // 定义静态常量
    int expiredays = 365;                          // 定义静态常量(省略 public static final)

}

// 接口 2
public interface VirtualGoods {
}


// 实现接口的类 1 
public class Product implements Expired,VirtualGoods {

    @Override
    public boolean isOnSale() {
        return true;
    }

    @Override
    public int saledays(int day) {
        return (int)(day * 0.95);
    }

    @Override
    public void expireday() {						// 注意这个方法的实现
        System.out.println("Total :"+expiredays);
    }
}

// 实现接口的类 2
public class Goods implements Expired{
    @Override
    public boolean isOnSale() {
        return false;
    }

    @Override
    public int saledays(int day) {
        return 0;
    }

    @Override
    public void expireday() {						// 注意这个方法的实现
        System.out.println("Never expire!");
    }
}

// 调用类
public class TestUse {
    public static void main(String[] args) {
        Expired exp = new Product();
        Expired exp2 = new Goods();
        exp.expireday();                    // Total :365
        exp2.expireday();                   // Never expire!
        Product product = (Product) exp;
        VirtualGoods vir = (VirtualGoods) exp;		// 不报错
//        VirtualGoods vir2 = (VirtualGoods) exp2;    // 报错。无法将 Goods 转换成 VirtualGoods
//        Goods goods = (Goods)exp;       // 报错。无法将 Product 转换成 Goods
        product.expireday();                // Total :365
        System.out.println(exp instanceof Product);         // true
        System.out.println(exp2 instanceof Product);        // false
        System.out.println(exp2 instanceof Goods);          // true
        System.out.println(exp2 instanceof Expired);        // true
        System.out.println(exp instanceof Expired);         // true
        System.out.println(exp instanceof VirtualGoods);    // true
    }
}

// 即关于子类实例给父类引用赋值、父类引用(实际指向子类实例)可以强制转换成子类后给子类引用赋值。继承和接口实现的表现是一样的。

IDEA 快捷自动实现接口

可以借助 IDEA 快速实现接口的所有抽象方法。当然这个实现只是搭建出一个不报错的代码框架,里面的方法体内容还是需要我们根据业务逻辑去编写的。

public class Product implements Expired,VirtualGoods {

}

将光标定位到接口处,按下 alt + enter ,在弹出的下拉框中点击 Implement methods,选中要自动实现的抽象方法,点击 OK 确认生成,就会得到如下代码框架,再根据需要自行编写代码。

public class Product implements Expired,VirtualGoods {
    @Override
    public boolean isOnSale() {
        return false;
    }

    @Override
    public int saledays(int day) {
        return 0;
    }

    @Override
    public void expireday() {

    }
}

接口的继承

接口也可以继承接口。

接口可以继承多个接口,接口之间的继承也是用 extends

继承的接口,可以有重复的方法,但是签名相同时,返回值必须完全一样,否则会有编译错误。

  • 当然如果是方法名一样,但参数类型不一样(方法签名不完全相同)则是允许返回类型不同的(方法重载)。
public interface Intf1 {
    void m1();
}

public interface Intf2 {
    int m1();
    void m2();
}

public interface Intf3 extends Intf1,Intf2 {			// 报错,因为 Intf2 的 int m1() 与 Intf1 的 void m1() 冲突了(签名一样,返回值类型不一样,并且若定义为一个 double 另一个 int,仍然会报错,并不存在类型兼容的情形)
    void m3();
}

接口是否属于多继承?

接口虽然可以继承自多个接口,但和真正的多继承还是有区别的。因为接口本身没有成员变量,所以无论是类实现多个接口,还是接口继承自多个接口,都只能获得一堆方法(并且方法也是有限制的),而不会获得成员变量。这和多继承还是有区别的。

从不同接口继承相同方法

如果继承两个接口,两个接口里有同样的抽象方法(均无缺省实现),这是没有问题的。

但如果一个类实现了两个接口,并且两个接口里有相同的缺省方法,编译器会报错。

因为这样一来,java 也无法判别到底对于这个方法,是以哪个接口中的缺省方法作为方法体,所以报错。

  1. 从不同接口,继承相同的抽象方法(均无缺省实现)
public interface Intf1 {
    void m1();
}

public interface Intf2 {
    void m1();
}

public interface Intf3 extends Intf1,Intf2 {
}

// 实现接口的类
public  class Test implements Intf3 {
    @Override
    public void m1() {

    }
}

// 调用类
public class TestUse extends Test{
    public static void main(String[] args) {
        Test a = new Test();					// 正常编译运行
    }
}

  1. 从不同接口,继承相同的抽象方法,其中一个有缺省实现。
// 实现接口的类不覆盖实现该抽象方法
public interface Intf1 {
    default void m1(){};
}
public interface Intf2 {
    void m1();
}
public interface Intf3 extends Intf1,Intf2 {

}
public  class Test implements Intf3 {

}
public class TestUse extends Test{
    public static void main(String[] args) {
        Test a = new Test();					// 报错。java: 类型 Intf1 和 Intf2 不兼容;接口 Intf3从类型 Intf1 和 Intf2 中继承了m1() 的抽象和默认值
    }
}

// 要想不报错,做以下尝试:
// 1. 在接口中加入对抽象方法的覆盖实现
// 调用 Intf1 中的 default 方法
public interface Intf3 extends Intf1,Intf2 {
    @Override
    default void m1() {
        Intf1.super.m1();
        // 若改为以下两种方式,会报错。
        // Intf1.m1();		// 报错:java: 无法从静态上下文中引用非静态 方法 m1()
        // 或
        // super.m1();		// 报错:找不到变量 super。
    }
}
// 或自己重新写一个方法覆盖
public interface Intf3 extends Intf1,Intf2 {
    @Override
    default void m1() {
												// 留空也能正常运行
    }
}

// 2. 不在 Intf3 中修改,而在 Test 对抽象方法进行实现覆盖。
public  class Test implements Intf3 {
    public void m1(){
        System.out.println("abc");
    }
}
// 实测,仍旧会报错:java: 类型 Intf1 和 Intf2 不兼容;接口 Intf3从类型 Intf1 和 Intf2 中继承了m1() 的抽象和默认值

// 3. 在 Intf3 中重新声明为抽象方法,然后在 Test 中对抽象方法进行覆盖实现。
public interface Intf3 extends Intf1,Intf2 {
    void m1();
}
public  class Test implements Intf3 {
    @Override
    public void m1() {
												// 留空也能正常运行
    }
}


// 综上所述:
// 从不同接口中继承相同的抽象方法,其中一个有缺省实现,必须在发生继承冲突的节点(例子中是 Intf3 接口)处覆盖实现该抽象方法(可以重新写,或在覆盖方法中调用有缺省方法体的那个接口的抽象方法,或重新声明为无缺省实现的抽象方法),否则报错。
  1. 从不同接口,继承相同的抽象方法,两个都有缺省实现。
// 缺省方法体实际内容相同
public interface Intf1 {
    default void m1(){};
}
public interface Intf2 {
    default void m1(){};
}
public interface Intf3 extends Intf1,Intf2 {    // 报错:java: 接口 Intf3 从类型 Intf1 和  Intf2 中继承了 m1() 的不相关默认值

}
public  class Test implements Intf3 {
    
}
public class TestUse{
    public static void main(String[] args) {
        Test a = new Test();					
    }
}

// 要不报错,做以下尝试:
// 1. 在接口中加入对抽象方法的覆盖实现
// 调用 Intf1 中的 default 方法
public interface Intf3 extends Intf1,Intf2 {
    @Override
    default void m1() {
        // Intf2.super.m1();		// 也是可以的。
        Intf1.super.m1();
        // 若改为以下两种方式,会报错。
        // Intf1.m1();		// 报错:java: 无法从静态上下文中引用非静态 方法 m1()
        // 或
        // super.m1();		// 报错:找不到变量 super。
    }
} 
// 或自己重新写一个方法覆盖
public interface Intf3 extends Intf1,Intf2 {
    @Override
    default void m1() {
												// 留空也能正常运行
    }
}

// 2. 不在 Intf3 中修改,而在 Test 对抽象方法进行实现覆盖。
public  class Test implements Intf3 {
    public void m1(){
        System.out.println("abc");
    }
}
// 实测,仍旧会报错:java: 接口 Intf3从类型 Intf1 和 Intf2 中继承了 m1() 的不相关默认值(报错仍旧发生在 Intf3 接口定义处)

// 3. 在 Intf3 中重新声明为抽象方法,然后在 Test 中对抽象方法进行覆盖实现。
public interface Intf3 extends Intf1,Intf2 {
    void m1();
}
public  class Test implements Intf3 {
    @Override
    public void m1() {
												// 留空也能正常运行
    }
}


// 缺省方法体实际内容不同
public interface Intf1 {
    default void m1(){};
}
public interface Intf2 {
    default void m1(){
        System.out.println();
    };
}

// 实测,和上面的情况一致,没有任何区别,都需要在 Intf3 中进行方法覆盖。

// 综上所述:
// 从不同接口中继承相同的抽象方法,其中两个都有缺省实现(无论方法体中实际内容是否相同),必须在发生继承冲突的节点(例子中是 Intf3 接口)处覆盖实现该抽象方法(可以重新写,或在覆盖方法中调用有缺省方法体的那个接口的抽象方法,或重新声明为无缺省实现的抽象方法),否则报错。

结论:当继承两个(或以上)接口,不同接口有相同的抽象方法(返回值类型相同+方法签名相同),只要其中有一个缺省实现的方法体(不论其他接口中是否也有缺省实现/缺省实现代码实际是否相同),就要在发生继承冲突(extends)的当前接口/发生实现冲突(implements)的当前类中覆盖该抽象方法(反正就是在继承发生交汇冲突的那个节点进行覆盖),否则报错。

  • 其中,这个在冲突交汇点的“覆盖”实现,其实还可以是重新去掉方法体,声明为不带缺省实现的抽象方法。

阻绝抽象方法的缺省实现

实现接口或用接口继承接口后,面对有缺省实现的抽象方法,可以有 3 种选择:

  1. 默默继承(extends)/实现(implements)这个抽象方法的缺省实现;

  2. 在当前类中覆盖实现该抽象方法(替代原本的缺省方法)/当前接口中重新用另一个缺省方法体覆盖父接口中的的缺省方法;

  3. 阻绝来自父接口的抽象方法缺省实现,将该方法重新定义为抽象方法。(如果当前是类而非接口,则需要把类定义为抽象类)。

    阻绝的目的是让后续的子类不会使用到之前定义的缺省方法体。

抽象类

抽象类可以看作是接口和类的混合体。用 abstract 修饰的类就是抽象类。

抽象类可以有抽象方法,也可以没有抽象方法,但不管包不包含抽象方法,抽象类都不能被实例化。

即便抽象类不含抽象方法,也是有实际意义的,因为有些类从设计(业务逻辑)来说,就不应该被实例化,而是用来被普通子类继承,再将子类实例化的。

抽象类可以继承别的类或抽象类,也可以实现接口。

抽象类中的抽象方法可以是自己定义的,也可以是继承自接口的。

  • 这里说的继承自接口不是说抽象类可以 extends 接口。只有接口才能 extends 接口,抽象类和其他类一样,只能 implements 接口。只不过抽象类可以 implements 接口之后不去将接口中的抽象方法实现(写出方法体),也就是实际上抽象类的确是继承了该接口的抽象方法。

接口可以实现类似“多继承”的效果,但抽象类和普通类一样,只允许类的单继承。

抽象类也可以被抽象类继承。

与接口不同,抽象类中不但可以定义非抽象方法(普通的方法),方法还可以是非 public 的,可以是任意的(protected、缺省、private)。

// 接口
public interface Battery {
    public static final double batteryAmount = 1000;
    public abstract double getBatteryAmount();
    String getBatteryBrand();
}

// 抽象类
public abstract class Phone implements Battery {
    public String brand;
    protected String phoneCode = "ABC";						// 可以有非 public 属性

    protected abstract String getCountryOfOrigin();

    public void getCode() {									// 可以有非抽象方法。
        System.out.println("The phone code is: " + phoneCode);
    }
}

// 普通类
public class Iphone extends Phone{
    String countryOfOrigin = "China";

    public Iphone(){
        this.brand = "Apple";
    }
    @Override
    public double getBatteryAmount() {
        return batteryAmount;
    }

    @Override
    public String getBatteryBrand() {
        String batterBrand = brand + ".battery.co";
        return batterBrand;
    }

    @Override
    protected String getCountryOfOrigin() {
        return countryOfOrigin;
    }
}

// 调用类
public class TestUse {
    public static void main(String[] args) {
        Iphone iphone = new Iphone();
        System.out.println(iphone.brand);                   // Apple
		System.out.println(iphone.getCountryOfOrigin());    // China  
		System.out.println(iphone.countryOfOrigin);         // China
        iphone.getCode();                                   // The phone code is: ABC
        System.out.println(iphone.getBatteryAmount());      // 1000.0
        System.out.println(iphone.getBatteryBrand());       // Apple.battery.co


        Phone iphone2 = new Iphone();
        System.out.println(iphone2.brand);                  // Apple
        System.out.println(iphone2.getCountryOfOrigin());   // China
        // System.out.println(iphone2.countryOfOrigin);     // 报错。因为 Phone 类中是没有 countryOfOrigin 这个属性的。
        iphone2.getCode();                                  // The phone code is: ABC
        System.out.println(iphone2.getBatteryAmount());     // 1000.0
        System.out.println(iphone2.getBatteryBrand());      // Apple.battery.co

        Iphone iphone3 = (Iphone) iphone2;
        System.out.println(iphone3.getBatteryBrand());      // Apple.battery.co
        System.out.println(iphone3.countryOfOrigin);        // China

    }
}

抽象类 vs. 接口

其实接口从 java 8 抽象方法有了默认方法体,java 9 进一步有了 private 方法,就越来越像抽象类了,甚至你可以简单理解接口就是没有成员属性的抽象类。但接口本身定位是“制定规范”,所以业务逻辑的设计中,其实还是尽可能不要跑偏“制定规范”这个目的。

抽象类接口
被继承单继承被类多实现(implements)/被接口“多继承”(extends)
属性修饰符可以是任意的必须为 public static final(可以不写,不写也是这个)
方法修饰符可以是任意的必须为 public abstract(可以不写,不写也是这个)
实例化不能不能
引用被子类引用/子类实例赋值允许允许

如何让接口更像抽象类

因为接口和抽象类的一个很大区别就是接口是没有成员变量的,但接口其实最终是要被一个具体的类实现的,然后这个类可以有实例,实例就可以有属性。可以通过如下的思路设计,让接口更像一个抽象类。

// 接口
public interface Intf1 {
    String getName();		// 定义一个获取成员属性 name 的值的方法 

    default void sayHi(){
        System.out.println(getName() + " says 'hi!'");		// 通过 getName() 方法实现了类似成员属性的效果。
		// System.out.println(this.getName() + " says 'hi!'");       // 加不加 this 都行,这个this并不是指接口,而是实现接口的类的实例。所以虽然接口不能实例化,还是可以写 this 的。    
    }
}


// 实现接口的类
public class Nor1 implements Intf1 {
    private String name = "Tom";
    @Override
    public String getName() {		// 因为具体类是要覆盖抽象类的所有抽象方法的,所以一定会覆盖到这个方法
        return this.name;
    }
}


// 那么现在对于接口来说,其实就可以通过调用方法来实现类似“拥有成员变量”的效果的

// 调用类
public class TestUse {
    public static void main(String[] args) {
        Intf1 a = new Nor1();
        System.out.println(a.getName());			// Tom
        // System.out.println(a.name);				// 报错。而且即便声明  Nor1 a = Nor1(), name 在 Nor1 类中也是 private 的。
        a.sayHi();									// Tom says 'hi!'
    }
}
<think>嗯,用户想查找关于IEH正确性错误的原因及解决法,特别是ErrorStatus 0x20000x8,还有设备信息(S:0x1 B:0xC9 D:0x2 F:0x0),WHEA检测到PCIe错误。首先,我需要理解这些错误代码的含义。IEH可能是指Intel Error Handling,或者是某个特定硬件或驱动程序的错误处理机制。WHEA是Windows硬件错误架构,记录硬件相关的问题,所以这可能涉及到硬件故障或兼容性问题。 首先,ErrorStatus 0x20000x8的具体含义是什么?通常,WHEA错误状态码由多个位组成,每个位代表不同的错误类型。例如,0x2000可能对某个特定的错误位,需要查阅Intel或微软的文档。0x8可能表示内存或PCIe设备的问题。设备地址S:0x1 B:0xC9 D:0x2 F:0x0中的B:0xC9可能对总线号201,这可能帮助定位具体的PCIe设备,比如显卡、网卡或其他扩展卡。 接下来,用户提到WHEA记录的是纠正错误,说明系统检测到了可纠正的PCIe错误,这可能不会导致系统崩溃,但可能影响性能或稳定性。可能的原因包括硬件连接不良、驱动程序问题、固件过时、硬件故障或电源问题。 解决面,可能需要检查硬件连接,更新驱动和固件,运行诊断工具,检查电源,或者更换硬件。同时,查看系统日志和厂商工具可以进一步诊断问题。 需要确保引用的信息相关,比如引用[1]中的空间关系和设备位置可能硬件配置有关,引用[2]的压力测试可能涉及系统稳定性,引用[3]的批量重命名工具可能不相关,但用户的其他引用需要合理利用。 用户可能需要分步骤的解决案,从简单到复杂,比如先检查连接,再更新驱动,最后硬件替换。同时,解释错误代码的具体含义和如何定位问题设备是关键。</think>### IEH正确性错误分析及解决案 #### 一、错误代码解读 1. **ErrorStatus 0x2000** 该错误通常表示$PCIe\ Correctable\ Error$(可纠正的PCIe错误),属于硬件层通信协议错误,例如链路训练失败、CRC校验错误等[^1]。系统通过重试机制可自动修复,但高频出现可能预示硬件隐患。 2. **ErrorStatus 0x8** 对$Memory\ Hierarchy\ Error$(内存层次结构错误),可能由内存模块、CPU缓存或内存控制器异常引起[^2]。需注意此错误可能PCIe设备直接内存访问(DMA)相关。 3. **设备标识解析** $S:0x1\ B:0xC9\ D:0x2\ F:0x0$表示: - 总线编号$0xC9$(十进制201) - 设备号$0x2$ 可通过`lspci -nn -s 00:C9.2`(Linux)或设备管理器详细信息(Windows)定位具体设备。 #### 二、原因分析 | 别 | 具体原因 | 检测法 | |------|----------|----------| | 硬件故障 | PCIe插槽接触不良/金手指氧化<br>设备电容老化 | 物理检查+替换测试 | | 驱动问题 | 设备驱动版本不兼容<br>IRQ冲突 | 设备管理器错误代码<br>驱动验证程序 | | 固件缺陷 | 设备固件未更新<br>UEFI/BIOS版本过旧 | 厂商固件检测工具 | | 系统环境 | 超频导致信号不稳定<br>电源波纹超标 | HWInfo64监测<br>示波器检测 | #### 三、解决案 1. **硬件层操作** - 使用$99\%$浓度异丙醇清洁PCIe金手指 - 更换插槽测试(规避主板布线缺陷) - 使用PCIe信号增强卡(针对长距离传输场景) 2. **驱动/固件更新** ```powershell # PowerShell命令获取设备详情 Get-PnpDevice -InstanceId PCI\VEN_XXXX&DEV_XXXX ``` - 更新UEFI至支持$PCIe\ ASPM\ L1.2$的最新版本 - 安装经WHQL认证的驱动程序 3. **系统配置优化** 修改注册表增强错误处理: ```reg [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management] "HardwareErrors"=dword:00000001 ``` 4. **诊断工具使用** - Windows事件查看器过滤事件ID$1$(WHEA日志) - 运行`mdsched.exe`执行内存诊断 - 使用Intel® DSA检测平台健康状态 #### 四、进阶处理 若上述法无效,需进行$PCIe\ Link\ Training$分析: $$BER = \frac{1}{N}\sum_{i=1}^{N} (T_{eye\_width}[i] < T_{spec})$$ 通过示波器测量眼图张开度,计算误码率是否符合$PCIe\ Gen3\ BER \leq 10^{-12}$标准[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值