JAVA面向对象(下)(三、接口和代码块)

一、接口(难点、重点)

1.1 需求

  • 声明一个抽象父类Animal,包含public abstract void eat();

  • 声明一个子类Bird,继承Animal,

    • 重写eat方法

    • 新增一个方法:public void fly()

  • 声明一个Plane,没有继承Animal,也包含一个方法:public void fly()

package com.atguigu.jiekou;
​
public abstract class Animal {public abstract void eat();
}
package com.atguigu.jiekou;
​
public class Bird extends Animal{@Overridepublic void eat() {System.out.println("吃虫子");}public void fly(){System.out.println("我要飞的更高.....");}
}
package com.atguigu.jiekou;
​
public class Plane {public void fly(){System.out.println("我要飞入云霄");}
}

问题1:抽取共同父类

问题:此时Bird类与Plane类有共同的特征,即共同的fly方法,那么按照类的定义(一类具有相同特性的事物的抽象描述),应该把fly这个方法抽取到一个父类中。

package com.atguigu.jiekou;
​
public abstract class FlyThings {public abstract void fly();
}
​

问题2:遇到了Java的单继承限制

package com.atguigu.jiekou;
​
public class Bird extends Animal,FlyThings{ //错误代码@Overridepublic void eat() {System.out.println("吃虫子");}public void fly(){System.out.println("我要飞的更高.....");}
}
​

解决办法:引入接口

要声明一种与类相似的类型,但是又不会有单继承限制的问题,这样的类型就是接口。

1.2 接口的声明 interface

语法格式:

【权限修饰符】 interface 接口名{【权限修饰符】 abstract 返回值类型 方法名(【形参列表】); 
}

package com.atguigu.jiekou;
​
/*
public abstract class FlyThings {//不合适public abstract void fly();
}
*/
​
public interface FlyThings {public abstract void fly();
}
package com.atguigu.jiekou;
​
public interface RunThings {public abstract void run();
}
​

1.3 类与接口的实现关系 implements

语法格式:

【权限修饰符】 class 类名 extends 父类名 implements 父接口们{}

子类与父类直接只能是单继承。

子类与父接口之间是多实现,一个子类可以同时实现多个接口。

父类:比喻亲爹

父接口们:比喻干爹

package com.atguigu.jiekou;
​
public class Bird extends Animal implements FlyThings,RunThings{@Overridepublic void eat() {System.out.println("吃虫子");}
​@Overridepublic void fly(){System.out.println("我要飞的更高.....");}
​@Overridepublic void run() {System.out.println("我也会跑...");}
}
​
package com.atguigu.jiekou;
​
public class Plane implements FlyThings{@Overridepublic void fly(){System.out.println("我要飞入云霄");}
}
​

1.4 抽象类与接口的区别

接口可以多实现,抽象类只能单继承。

接口的关键字:interface,抽象类的关键字:abstract class。

1.5 接口的特点与要求

  • 接口也不能直接new对象。

  • 类与接口之间支持多实现。

  • 接口与接口之间支持多继承。

  • 子类(对于接口来说又称为实现类)实现接口时,如果子类不是抽象类,要求子类必须重写或实现父接口的所有的抽象方法。

  • 接口的成员有限制:

    • 成员变量只能是public static final,称为公共的静态的常量。public static final可以省略。

    • 接口没有构造器。

    • JDK8之前,接口中只能有公共的抽象方法,即public abstract。public abstract可以省略。

    • JDK8,接口中又增加了两种非抽象方法

      • 公共的静态方法:public static,这里的public可以省略。

      • 公共的默认方法:public default,这里的public可以省略。

      • 静态方法不允许被重写,默认方法允许实现类进行重写。

    • JDK9之后,接口中又增加了一种非抽象方法:

      • 私有的方法,可以是静态的,可以是非静态,但是不是默认的,不是抽象的。

示例代码1:接口的成员

package com.atguigu.jiekou;
​
public interface MyInter {//public static final 可以省略,完全是多余的//因为接口的成员变量必须是 public static final
//    public static final int VALUE = 1;int VALUE = 1;
​//public abstract可以省略,完全是多余的//因为接口中的抽象方法,必须是 public abstract
//    public abstract void fly();void fly();
​//JDK8之后//公共的静态方法1public static void fun1(){print();System.out.println("fun1");}//公共的静态方法2public static void fun2(){print();System.out.println("fun2");}//JDK9之后//私有的静态方法private static void print() {System.out.println("接口的静态方法");}
​//JDK8之后//公共的默认方法1public default void method1(){printDefault();System.out.println("method1");}//公共的默认方法2public default void method2(){printDefault();System.out.println("method2");}
​//JDK9之后//私有的方法private void printDefault() {System.out.println("接口的默认方法");}
}

示例代码2:接口之间多继承

package com.atguigu.jiekou;
​
public interface A {public abstract void a();
}
package com.atguigu.jiekou;
​
public interface B {public abstract void b();
}
package com.atguigu.jiekou;
​
public interface C extends A,B{public abstract void c();
}
package com.atguigu.jiekou;
​
public class D implements C{@Overridepublic void a() {
​}
​@Overridepublic void b() {
​}
​@Overridepublic void c() {
​}
}

1.6 接口与实现类对象构成多态引用

接口类型的变量与实现类对象之间也构成多态引用。这一点与父类变量与子类对象之间构成多态引用是一样的。

package com.atguigu.jiekou;
​
public class Kite implements FlyThings{@Overridepublic void fly() {System.out.println("我飞的再高,线也在你手里!");}
}

package com.atguigu.jiekou;
​
public class TestFlyThings {public static void main(String[] args) {
//        FlyThings f = new FlyThings();//错误//接口不可以直接new对象
​//现在想要调用Bird和Plane等的共同的方法 fly方法FlyThings[] all = new FlyThings[3];all[0] = new Bird();//多态引用。 左边all[0]是父接口FlyThings类型,右边是Bird实现类对象all[1] = new Plane();all[2] = new Kite();
​for (int i = 0; i < all.length; i++) {all[i].fly();}}
}

1.7 冲突情况

1.7.1 父类的成员变量与父接口的常量重名

package com.atguigu.chongtu;
​
public class Base {//父类int a = 1;
​
}
​
package com.atguigu.chongtu;
​
public interface BaseInter {int a = 2;
}
package com.atguigu.chongtu;
​
public class Sub extends Base implements BaseInter{public void test(){System.out.println("父类的a = " + super.a);System.out.println("父接口的a = " + BaseInter.a);//因为接口中的a是静态的,通过接口名称就可以方法}
}
​

1.7.2 父接口们的默认方法重名

父接口名.super.默认方法名(); 进行区别

package com.atguigu.chongtu;
​
public interface One {public default void m(){System.out.println("One.m默认方法");}
}
​
package com.atguigu.chongtu;
​
public interface Two {public default void m(){System.out.println("Two.m默认方法");}
}
​
package com.atguigu.chongtu;
​
public class Three implements One,Two{@Overridepublic void m() {One.super.m();//接收One父接口的}
}

1.7.3 父类的方法与父接口的默认方法重名

子类默认选择是父类的。

如果子类想要选择父接口的,必须通过 父接口名.super.默认方法名();

package com.atguigu.chongtu;
​
public class Fu {public void m(){System.out.println("Fu.m普通方法");}
}
​package com.atguigu.chongtu;
​
public interface GanBaBa{public default void m(){System.out.println("GanBaBa.m普通方法");}
}
​
package com.atguigu.chongtu;
​
public class Son extends Fu implements GanBaBa{@Overridepublic void m() {super.m();
//        GanBaBa.super.m();}
}
​
package com.atguigu.chongtu;
​
public class TestSon {public static void main(String[] args) {Son s = new Son();s.m();//Fu.m普通方法}
}

1.8 访问接口的成员

1.8.1 在其他类(例如测试类)中访问接口的成员

1、公共的静态的常量

接口名.静态常量名

2、公共的静态方法

接口名.静态方法名();

3、公共的抽象方法

接口名 变量名 = new 接口实现类(); //必须创建接口实现类的对象
变量名.抽象方法名();

4、公共的默认方法

接口名 变量名 = new 接口实现类(); //必须创建接口实现类的对象
变量名.默认方法名();
​
//如果实现类没有重写默认方法,仍然执行接口的默认方法体
//如果实现类重写了默认方法,执行重写后的方法体
MyInter接口
package com.atguigu.jiekou;
​
public interface MyInter {//public static final 可以省略,完全是多余的//因为接口的成员变量必须是 public static final
//    public static final int VALUE = 1;int VALUE = 1;
​//public abstract可以省略,完全是多余的//因为接口中的抽象方法,必须是 public abstract
//    public abstract void fly();void fly();
​//JDK8之后//公共的静态方法1public static void fun1(){print();System.out.println("fun1");}//公共的静态方法2public static void fun2(){print();System.out.println("fun2");}
​//JDK9之后//私有的静态方法private static void print() {System.out.println("接口的静态方法");}
​//JDK8之后//公共的默认方法1public default void method1(){printDefault();System.out.println("method1");}//公共的默认方法2public default void method2(){printDefault();System.out.println("method2");}
​//JDK9之后//私有的方法private void printDefault() {System.out.println("接口的默认方法");}
​
​
}
 
MySub实现类
package com.atguigu.jiekou;
​
public class MySub implements MyInter{@Overridepublic void fly() {System.out.println("重写接口的抽象方法");}
​//重写默认方法,default要去掉@Overridepublic void method1() {System.out.println("重写接口的默认方法method1");}
}

测试类
package com.atguigu.jiekou;
​
public class TestMyInter {public static void main(String[] args) {//访问MyInter接口的公共的静态常量System.out.println("MyInter.VALUE = " + MyInter.VALUE);
​//调用MyInter接口的公共的静态方法MyInter.fun1();MyInter.fun2();
​//调用MyInter接口的公共的抽象方法//调用MyInter接口的公共的默认方法MyInter my = new MySub();my.fly();//抽象方法my.method1();//默认方法my.method2();//默认方法}
}

1.8.2 在实现类中访问接口的成员

1、公共的静态的常量

情况一:没有重名问题

直接访问接口的公共的静态的常量,不需要加xx.

情况二:重名问题

父类的成员变量与父接口的常量重名了

super.成员变量 代表的是父类的
父接口名.常量  代表的是父接口的

2、公共的静态方法

实现类不会继承父接口的静态,也不能重写父接口的静态方法。

接口名.静态方法();

3、公共的默认方法

情况一:如果实现类没有重写父接口的默认方法或其他重名问题

默认方法名();

情况二:如果实现类重写父接口的默认方法或其他重名问题

父接口名.super.默认方法名();
YourInter父接口
package com.atguigu.jiekou;
​
public interface YourInter {
​public default void method2() {System.out.println("另一个父接口的默认方法method2");}
}

MySub子类/实现类
package com.atguigu.jiekou;
​
public class MySon implements MyInter,YourInter{@Overridepublic void fly() {System.out.println("重写接口的抽象方法");}
​//演示在实现类中,怎么调用或使用接口的各个成员public void test(){//使用父接口的公共的静态常量System.out.println("MyInter父接口的公共的静态常量:" + VALUE);
​//使用父接口的公共的静态方法
//        fun1();//接口的静态方法不会继承到实现类中,所以无法直接使用MyInter.fun1();MyInter.fun2();
​//使用父接口的默认方法method1();
//        method2();//调用自己重写的方法MyInter.super.method2();}
​@Overridepublic void method2() {System.out.println("实现类重写了父接口的默认方法method2");}
}
​
测试类
package com.atguigu.jiekou;
​
public class TestMySon {public static void main(String[] args) {MySon son = new MySon();son.test();}
}

1.9 关于静态方法重写的问题

结论:无论是父类的,还是父接口,静态方法都不能被重写。

父类的静态方法,可以被子类继承,可以通过 父类名.静态方法()(推荐), 子类名.静态方法(), 对象名.静态方法()。

父接口的静态方法,不可以被子类继承,唯一的调用方式:父接口名.静态方法()。

package com.atguigu.ask;
​
public class Fu {public static void m(){System.out.println("(1)Fu.m静态方法");}
}
​
package com.atguigu.ask;
​
public interface GanDie {public static void n(){System.out.println("(2)GanDie.n静态方法");}
}
package com.atguigu.ask;
​
public class Zi extends Fu implements GanDie{
//    @Override //加上它报错,因为它不是重写方法//这里只是Zi类自己又定义了一个同名,同参的方法//这种写法实际开发中,就不应该出现//因为父类的m方法是静态的,表示这个方法是全局共享,包括父类,子类都可以共享//那么子类就不能也不需要再定义一个同样的方法了。/*public static void m(){System.out.println("(3)Zi.m静态方法");}*/
​//下面这个方法,更是与接口中的n方法无关。public static void n(){System.out.println("(4)Zi.n静态方法");}
}
package com.atguigu.ask;
​
public class TestZi {public static void main(String[] args) {Fu f = new Zi();//多态引用f.m();/*假设Zi类可以重写Fu类的m方法,那么就会遵循:编译看左边,运行看右边。执行的结果是(3)但是 执行的结果是(1),说明Zi类中m()方法并未重写(覆盖,覆写)Fu的m方法*/System.out.println("==================");Zi.m();//要么用子类名调用它Zi z = new Zi();z.m();//要么用子类对象调用它
​System.out.println("==================");Fu.m();Zi.m();//如果Zi类没有自定定义m()方法,那么它这种方式也可以调用父类的静态方法m
​System.out.println("=======================");
​GanDie g = new Zi();// g.n();//错误,编译器直接报错,//因为接口的静态方法,不能继承到子类中,唯一调用方式就是 接口名.静态方法GanDie.n();Zi.n();}
}
​

1.10 接口的应用场景

问题:

  • 编写一个数组工具类

    • 方法1:可以给所有int[]数组实现排序,从小到大

    • 方法2:可以给所有对象数组实现排序,从小到大

问题1:对象无法直接比较大小

package com.atguigu.tools;
​
import java.util.Comparator;
​
public class MyArrayTools {public static void sort(int[] arr){for(int i=0; i<arr.length-1; i++){for(int j=0; j<arr.length-1-i; j++){if(arr[j] > arr[j+1]){int temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}}
​/*Object[]类型表示可以接收所有对象数组。*/public static void sort(Object[] arr){for(int i=0; i<arr.length-1; i++){for(int j=0; j<arr.length-1-i; j++){// arr[j]和 arr[j+1]里面存储的都是对象的首地址,首地址是无法比较大小。if(arr[j].xx > arr[j+1].xx){//报错Object temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}}
}

解决:用比较器接口Comparator

Java的核心类库中有一个比较器接口:java.util.Comparator,这个接口有一个抽象方法 int compare(Object o1, Object o2),这个抽象方法用于确定如何比较两个对象的大小。规定:

  • o1 > o2 返回正整数

  • o1 < o2 返回负整数

  • o1 = o2 返回0

自定义数组工具类
package com.atguigu.tools;
​
import java.util.Comparator;
​
public class MyArrayTools {public static void sort(int[] arr){for(int i=0; i<arr.length-1; i++){for(int j=0; j<arr.length-1-i; j++){if(arr[j] > arr[j+1]){int temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}}
​/*Object[]类型表示可以接收所有对象数组。多态的应用:形参1是Object[]数组类型实参可能是String[],可能是Employee[],可能是Rectangle[]等
​形参2是Comparator接口类型,而且compare方法是一个抽象方法,没有方法体实参一定 Comparator接口的实现类对象,实现类必须重写compare方法*/public static void sort(Object[] arr, Comparator com){for(int i=0; i<arr.length-1; i++){for(int j=0; j<arr.length-1-i; j++){/*arr[j]和 arr[j+1]里面存储的都是对象的首地址,首地址是无法比较大小。
​
//                if(arr[j].xx > arr[j+1].xx)//(1)我们在写sort方法时,并不能确定 数组元素的运行时类型是什么,所以,无法确定该.xx//(2)也无法进行向下转型,因为不知道该向下转为什么类型//这是是一个通用方法,适用于所有的对象数组的排序方法
​使用Comparator接口的compare方法,来比较 arr[j], arr[j+1]元素的大小。int compare(Object o1, Object o2),这个抽象方法用于确定如何比较两个对象的大小。规定:- o1 > o2 返回正整数- o1 < o2 返回负整数- o1 = o2 返回0
​com.compare(arr[j], arr[j+1]) >0表示 arr[j] 大于 arr[j+1]*/if(com.compare(arr[j], arr[j+1]) >0){Object temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}}}}
}
​

案例1
矩形类
package com.atguigu.tools;
​
public class Rectangle {private double length;private double width;
​public Rectangle() {}
​public Rectangle(double length, double width) {this.length = length;this.width = width;}
​public double getLength() {return length;}
​public void setLength(double length) {this.length = length;}
​public double getWidth() {return width;}
​public void setWidth(double width) {this.width = width;}
​@Overridepublic String toString() {return "Rectangle{" +"length=" + length +", width=" + width +'}';}
}
​

矩形比较器实现类
package com.atguigu.tools;
​
import java.util.Comparator;
​
public class RectangleComparator implements Comparator {/*这里也是多态的应用:形参的类型是Object类型,实参的类型应该是Rectangle类型,因为这个比较器对象用于比较两个矩形对象的length值的大小*/@Overridepublic int compare(Object o1, Object o2) {//在这里要明确,如何比较两个Rectangle矩形对象的大小//这里为了调用Rectangle的getLength方法,怎么办?必须向下转型Rectangle r1 = (Rectangle) o1;Rectangle r2 = (Rectangle) o2;//r1的length 大于 r2的length 返回正整数//r1的length 小于 r2的length 返回负整数//r1的length 等于 r2的length 返回0if(r1.getLength() > r2.getLength()){return 1;}else if(r1.getLength() < r2.getLength()){return -1;}else{return 0;}}
}

矩形数组测试类
package com.atguigu.tools;
​
public class TestRectangles {public static void main(String[] args) {Rectangle[] rectangles = new Rectangle[5];//随机产生矩形的长和宽的值,范围[0,10)for (int i = 0; i < rectangles.length; i++) {int length = (int)(Math.random()*10);int width = (int)(Math.random()*10);rectangles[i] = new Rectangle(length, width);System.out.println(rectangles[i]);}
​System.out.println("排序(按照length值从小到大排序):");RectangleComparator rc = new RectangleComparator();MyArrayTools.sort(rectangles, rc);//排序后,输出结果for (int i = 0; i < rectangles.length; i++) {System.out.println(rectangles[i]);}}
}
 
案例2
员工类
package com.atguigu.tools;
​
public class Employee {private int id;private String name;private int age;private double salary;//薪资
​public Employee() {}
​public Employee(int id, String name, int age, double salary) {this.id = id;this.name = name;this.age = age;this.salary = salary;}
​public int getId() {return id;}
​public void setId(int id) {this.id = id;}
​public String getName() {return name;}
​public void setName(String name) {this.name = name;}
​public int getAge() {return age;}
​public void setAge(int age) {this.age = age;}
​public double getSalary() {return salary;}
​public void setSalary(double salary) {this.salary = salary;}
​@Overridepublic String toString() {return "Employee{" +"id=" + id +", name='" + name + '\'' +", age=" + age +", salary=" + salary +'}';}
}
 
员工比较器实现类
package com.atguigu.tools;
​
import java.util.Comparator;
​
public class EmployeeAgeComparator implements Comparator {@Overridepublic int compare(Object o1, Object o2) {Employee e1 = (Employee) o1;Employee e2 = (Employee) o2;return e1.getAge() - e2.getAge();}
}
 
员工数组测试类
package com.atguigu.tools;
​
public class TestEmployees {public static void main(String[] args) {Employee[] arr = new Employee[4];arr[0] = new Employee(1,"张三",23,15000);arr[1] = new Employee(2,"李四",21,16000);arr[2] = new Employee(3,"王五",22,12000);arr[3] = new Employee(4,"赵六",24,18000);
​for (int i = 0; i < arr.length; i++) {System.out.println(arr[i]);}
​System.out.println("按照年龄从小到大排序:");//按照年龄从小到大排序EmployeeAgeComparator ec = new EmployeeAgeComparator();MyArrayTools.sort(arr,ec );//输出排序后的结果for (int i = 0; i < arr.length; i++) {System.out.println(arr[i]);}}
}

结论

把众多不相关的类对象的共同行为方法提取出来,构成接口。用接口来管理这些实现类的对象。

例如:

  • Bird(鸟)、Plane(飞机)、Kite(风筝)等共同行为方法void fly() 提前出来 ,构成FlyThings 接口。请看$2.6 小节。

  • Rectangle(矩形)、Employee(员工)等共同行为方法 int compare(对象1,对象2)提前出来,构成Comparator接口。请看$2.10小节。

1.11 代码块(了解)

类的成员: (1)成员变量(重要) (2)构造器(重要) (3)成员方法(重要) (4)代码块(了解)

1、代码块的分类

有两种:

(1)静态代码块

(2)非静态代码块

【修饰符】 class 类名{static{//静态代码块}{//非静态代码块}
}
package com.atguigu.block;
​
public class Demo {
/*    int a = 1;System.out.println("a = " + a);//这些代码不应该在方法外,即方法外面是不能写语句*/
​{int a = 1;System.out.println("a = " + a);//代码块中,就和方法体中一样,可以写语句}
}

2、静态代码块(偶尔会用)

(1)静态代码块的作用:为类的静态变量进行初始化。

(2)什么时候执行:在类加载时初始化完最后执行,而且一个类只会被加载1次。

(3)如果有父子类,先加载父类后加载子类。如果父类加载过了,不会重复加载。

示例代码
package com.atguigu.block;
​
public class DemoA {private static int num ;
​static {System.out.println("初始化之前num = " + num);//例如:随机产生[0,100)之间的整数为num赋值num = (int)(Math.random() * 100);//这里这是一个简单的例子,后期咱们为静态变量的赋值可能需要读取配置文件等复杂的代码才能完成初始化,就必须用代码块System.out.println("初始化之后num = " + num);}
​
​public static void fun(){System.out.println("DemoA.fun静态方法");}
}
​package com.atguigu.block;
​
public class TestDemoA {public static void main(String[] args) {DemoA.fun();}
}
 
示例代码
package com.atguigu.block;
​
public class DemoB {static {System.out.println("DemoB的静态代码块");}
}
​package com.atguigu.block;
​
public class SubDemoB extends DemoB{static {System.out.println("SubDemoB静态代码块");}
}
​
package com.atguigu.block;
​
public class TestSubDemoB {public static void main(String[] args) {DemoB d = new DemoB();System.out.println("===============");SubDemoB s = new SubDemoB();}
}
 

3、非静态代码块(除了面试题,几乎不用)

(1)非静态代码块的作用:为实例变量初始化。这一点与构造器的作用相同。所以非静态代码块和构造器的代码一定是一起执行的。

(2)执行特点:

  • 每次new对象时执行,每new一次,执行1次。

  • 非静态代码块比构造器的初始化代码要早执行。

示例代码
package com.atguigu.block;
​
public class ExampleA {int num;
​
​public ExampleA(){System.out.println("(2)无参构造");}
​public ExampleA(int num){System.out.println("(3)有参构造初始化之前:num = " + this.num);this.num = num;System.out.println("(3)有参构造初始化之后:num = " + this.num);}
​{System.out.println("(1)非静态代码块,初始化之前num = " + num);num = (int)(Math.random()*100);System.out.println("(1)非静态代码块,初始化之后num = " + num);}
​public static void fun(){System.out.println("ExampleA.fun静态方法");}
}
​package com.atguigu.block;
​
public class TestExampleA {public static void main(String[] args) {ExampleA.fun();//不会执行构造器和非静态代码块,因为没有new对象。
​System.out.println("================");ExampleA a1 = new ExampleA();//调用无参构造创建对象
​System.out.println("=================");ExampleA a2 = new ExampleA(200);}
}
 
示例代码
  • 先完成类的加载,再new对象

  • new对象时,子类的构造器一定会调用父类的构造器。父类的非静态代码块一定和父类的构造器一起执行。子类的非静态代码块与子类的构造器一起执行。

package com.atguigu.block;
​
public class ExampleB {static {System.out.println("(5)ExampleB父类的静态代码块");}{System.out.println("(1)ExampleB父类的非静态代码块");}
​public ExampleB(){System.out.println("(2)ExampleB父类无参构造");}
}
​
package com.atguigu.block;
​
public class SubExampleB extends ExampleB{static {System.out.println("(6)SubExampleB子类的静态代码块");}{System.out.println("(3)SubExampleB子类的非静态代码块");}
​public SubExampleB(){super();System.out.println("(4)SubExampleB子类无参构造");}
}
​
package com.atguigu.block;
​
public class TestSubExampleB {public static void main(String[] args) {SubExampleB b = new SubExampleB();}
}
//5,6,1,2,3,4

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/630.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python实现本地视频/音频播放器

Python实现本地视频/音频播放器 在Python中&#xff0c;有几个库可以用于视频播放&#xff0c;但是没有一个库是完美的&#xff0c;因为它们可能依赖于外部软件或有一些限制。 先看介绍用Python实现本地视频播放器&#xff0c;再介绍用Python实现本地音乐播放器。 Python实现…

【御控物联】Java JSON结构转换(4):对象To对象——规则属性重组

文章目录 一、JSON结构转换是什么&#xff1f;二、术语解释三、案例之《JSON对象 To JSON对象》四、代码实现五、在线转换工具六、技术资料 一、JSON结构转换是什么&#xff1f; JSON结构转换指的是将一个JSON对象或JSON数组按照一定规则进行重组、筛选、映射或转换&#xff0…

探索异常传播:深入剖析Python中的错误处理机制

文章目录 1. 异常传播的基本原理2. 复杂的异常传播场景3. 再次抛出异常的意义是什么&#xff1f;4. 最佳实践与异常处理策略 理解异常传播&#xff08;也称为异常冒泡&#xff09;的过程是至关重要的。这一机制确保当在程序执行中发生错误时&#xff0c;错误能被有效地捕获和处…

【前端Vue】Vue3+Pinia小兔鲜电商项目第6篇:整体认识和路由配置,本资源由 收集整理【附代码文档】

Vue3ElementPlusPinia开发小兔鲜电商项目完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;认识Vue3&#xff0c;使用create-vue搭建Vue3项目1. Vue3组合式API体验,2. Vue3更多的优势,1. 认识create-vue,2. 使用create-vue创建项目,1. setup选项的写法和执行…

为什么选择TikTok直播专线而不是节点?

TikTok直播已成为许多商家的重要营销手段&#xff0c;而网络质量作为营销直播效果的关键因素&#xff0c;使得商家们开始应用TikTok直播专线。虽然与节点相比&#xff0c;专线的价格稍高&#xff0c;但更多商家都倾向于选择TikTok直播专线。那么&#xff0c;为什么TikTok直播更…

盒子模型之怪异盒模型

这个是标准盒模型 这个是怪异盒模型 box-sizing:content-box;默认是标准盒模型 box-sizing:border-box;是怪异盒模型&#xff0c;会挤压里面的内容&#xff0c;不管怎么设置边框始终都是当初设置的200px <!DOCTYPE html> <html lang"en"> <head>…

分类分析模型

目录 1.目的 2.内容 2.1决策树分类模型 2.2K近邻分类模型 3.代码实现 3.1分类分析模型 3.2K近邻分类模型 1.目的 掌握利用Python语言及相关库编写决策树分类分析模型的方法&#xff0c;所构建的决策树能够对给定的数据集进行分类。掌握利用Python语言及相关库编写K近邻分…

Android多线程:Handler runOnUiThread 异步消息处理机制

目录 一&#xff0c;Android中的多线程问题 1.模拟耗时工作 2.Android开启子线程 二&#xff0c;在子线程中更新UI 1.异步消息处理机制 Handler 2.使用runOnUiThread更新UI 一&#xff0c;Android中的多线程问题 Android用户界面是与用户交互的接口&#xff0c;对于用户的…

免费ssl通配符证书申请教程

在互联网安全日益受到重视的今天&#xff0c;启用HTTPS已经成为网站运营的基本要求。它不仅保障用户数据传输的安全&#xff0c;提升搜索引擎排名&#xff0c;还能增强用户对网站的信任。通配符证书是一种SSL/TLS证书&#xff0c;用于同时保护一个域名及其所有下一级子域名的安…

CSS基础:display的3个常见属性值详解

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。 云桃桃-大专生&#xff0c;一枚程序媛&#xff0c;感谢关注。回复 “前端基础题”&#xff0c;可免费获得前端基础 100 题汇总&#xff0c;回复 “前端工具”&#xff0c;可获取 Web 开发工具…

Flutter第九弹 构建列表元素间距

目标&#xff1a; 1&#xff09;Flutter Widget组件之间间距怎么表示&#xff1f; 2&#xff09;列表怎么定义子项之间间距&#xff1f; 一、间距的表示组件 列表组件的间距一般采用固定间距&#xff0c;间距占据可见的空间。 已经使用的表示间距的组件 Spacer&#xff1a…

MATLAB实现遗传算法优化公铁水联运

公铁水联运是运输行业的经典问题, 常用智能算法进行优化,比如遗传算法. 公铁水多式联运优化的数学模型如下&#xff1a; 1.模型简介 公铁水多式联运优化问题可以抽象为一个网络流问题&#xff0c;其中节点代表不同的运输方式转换点&#xff08;如公路、铁路、水运的交汇点&a…

x264编码器 MV 预测

H264 编码标准中MV预测的目的 每个分割 MV 的编码需要相当数目的比特,特别是使用小分割尺寸时。为减少传输比特数,可利用邻近分割的 MV 较强的相关性,MV 可由邻近已编码分割的 MV 预测而得。预测矢量 MVp 基于已计算 MV 和 MVD(预测与当前的差异)并被编码和传送。MVp 则取决…

【C++航海王:追寻罗杰的编程之路】C++11(上)

目录 1 -> C11简介 2 -> 统一的列表初始化 2.1 -> {}初始化 2.2 -> std::initializer_list 3 -> 声明 3.1 -> auto 3.2 -> decltype 3.3 -> nullptr 1 -> C11简介 在2003年C标准委员会曾经提交了一份技术勘误表(简称TC1)&#xff0c;使得C…

解决跨域和https不能访问的问题。

本地安装了项目,是一键安装的,安装之后还是apache的web服务器,有个视频服务用的是https的服务,要对这个项目进行二次开发,本地调用没问题,可是别人已调用就跨域。只能本地访问。 现在有两个问题:1.解决跨域问题 2.还要解决https访问的问题。 解决思路,用nginx 的ssl证…

网络编程套接字(三)之TCP服务器简单实现

目录 一、服务端TcpServer 1、tcp_server.hpp 2、tcp_server.cc 二、客户端TcpClient tcp_client.cc 三、服务器和客户端进行通信 四、完整代码 一、服务端TcpServer 首先我们需要对服务端进行封装。我们需要的成员变量有IP地址&#xff0c;端口号port&#xff0c;以及监…

CentOS7下安装mysql8或者mysql5.7

mysql8 1、下载 访问mysql官网下载mysql8软件包 https://dev.mysql.com/downloads/mysql/ 选择相应的版本如&#xff1a;RPM Bundle mysql-8.0.33-1.el7.x86_64.rpm-bundle.tar RPM Bundle 8.0.33 下载地址&#xff1a;https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.…

Android的一些总结

先打开自定义的app显示欢迎->消失 打开桌面应用程序->在桌面应用程序中也要能一键启动打开视频播放的app 桌面应用程序广播接收者进行监听&#xff0c;然后打开服务/activity是可行的。 ########################## 日志&#xff0c;调试&#xff1a; Usb 无线 串口…

Vue3从入门到实战:深度了解相关API

shallowRef 作用&#xff1a;创建一个响应式数据&#xff0c;但只对顶层属性进行响应式处理。 用法&#xff1a; let myVar shallowRef(initialValue); 特点&#xff1a;只跟踪引用值的变化&#xff0c;不关心值内部的属性变化。 shallowReactive 作用&#xff1a;创建一个…

【MySQL】表的基本约束

文章目录 1、约束类型1.1NOT NULL约束1.2UNIQUE&#xff1a;唯一约束1.3DEFAULT&#xff1a;默认值约束1.4PRIMARY KEY&#xff1a;主键约束1.5FOREIGN KEY&#xff1a;外键约束 2、表的设计2.1一对一2.2一对多2.3多对多 1、约束类型 关键字解释NOT NULL指示某列不能存储NULL值…