龙空技术网

「Java 面向对象知识整理」面向对象重点

巴掌大叔 239

前言:

现时兄弟们对“java且与或”大概比较关注,同学们都需要学习一些“java且与或”的相关内容。那么小编在网摘上收集了一些对于“java且与或””的相关内容,希望小伙伴们能喜欢,大家快快来了解一下吧!

方法重载

方法重载(Overload)指方法名相同,形参列表不同的方法。Java 通过参数类型来判断该方法是否为重载方法。修饰符不同或返回值类型不同的方法不能称为方法重载!

例如:

public void show() {    System.out.println("哦吼?");}public void show(String name) {    System.out.println("商品名:"+ name);}public void show(String name, double price) {    System.out.println("商品名:" + name + ", 价格:" + price);}public static void main(String[] args) {    show();            // 哦吼?    show("手机");       // 商品名:手机    show("平板", 3000); // 商品名:平板, 价格:3000}
构造器重载

构造器重载要求形参列表不同

例如:

class Dog{  private String name;  private int age;  public Dog(){    // 无参构造  }  public Dog(String name){    this.name = name;  }  public Dog(String name, int age){    this.name = name;    this.age = age;  }}

这里有个问题,就是当需要为某个成员统一修改时,可能需要一一修改构造器。例如,需要在name成员前添加Dog: 的前缀,需要一一修改构造器。

这里可以通过this(参数)来调用对应的构造方法。

class Dog{  private String name;  private int age;  public Dog(){    // 无参构造  }  public Dog(String name){    this.name = "Dog: " + name;  }  public Dog(String name, int age){    this(name);  // 调用 `public Dog(String)` 构造器    this.age = age;  }}
方法重写

方法重写(Override)是指子类父类的方法重写。方法重写要求方法名、形参列表相同,返回值类型、声明抛出的异常相同或更小(即子类),访问权限相同或更大

重写的方法通常使用@Override注解来修饰(避免重写错代码)。

例如:

class Bird {  public void fly() {    System.out.println("鸟飞咯");  }}class Ostrich extends Bird {  @Override  public void fly() {    System.out.println("鸵鸟不会飞……");  }}
toString 与 equals 方法

toString方法是将当前对象以文本的方式来表示出来,Java 默认的toString方法是类名@哈希码的格式,通常我们重写该方法将其内部的成员变量表示出来。

equals方法则是用于比较两个对象是否相同,Java 默认通过比较两个引用变量是否指向同一个对象,通常我们重写该方法使用该类的关键属性来比较。

class Person {  private String name;  private int age;  // 有参构造  public Person(String name, int age) {    this.name = name;    this.age = age;  }  // Getter / Setter 方法  public void setName(String name) {    this.name = name;  }  public void setAge(int age) {    this.age = age;  }  public String getName() {    return this.name;  }  public int getAge() {    return this.age;  }  // toString 方法  @Override  public String toString() {    return "Person[name=" + name         + ", age=" + age         + "]";  }  // equals 方法  @Override  public boolean equals(Object obj) {    if (this == obj) return true;  // 同一个对象    if (obj != null && obj.getClass() == Person.class) {      // obj不为null且obj和当前对象的类相同      Person target = (Person) obj;      return this.name.equals(target.getName())             // String类型需要使用equals方法比较          && this.age == target.getAge();    }    return false;  }}public class PersonTest {  public static void main(String[] args) {    Person p1 = new Person("王强", 18);    Person p2 = new Person("王强", 18);    Person p3 = new Person("张三", 30);    System.out.println(p1);     // Person[name=王强, age=18]    System.out.println(p2);     // Person[name=王强, age=18]    System.out.println(p3.toString()); // Person[name=张三, age=30]    if (p1.equals(p2))          // true      System.out.println("p1和p2是同一个人");  }}
hashCode 方法

将在 Collection 部分补充。

初始化块

初始化块的语法如下:

[修饰符] {  // ...}

其中修饰符只能出现static,无static修饰的称为实例初始化块,有static修饰的称为类初始化块

实例初始化块

实例初始化块实际上是「假象」,块中所有代码在编译时将会被还原到每个构造器的最前面。左图为编译前的原始代码,右图为class文件反编译的代码。

实例初始化块的作用是将各个构造器前相同的代码抽离到实例初始化块,从而实现代码复用

Something mysterious:

类初始化块

类初始化块负责对类进行初始化。当程序第一次主动使用(除了仅使用该类声明变量)该类时,系统会为该类分配内存空间,并调用类初始化块。程序运行时,该类初始化块只执行一次。

执行次数

执行先后

执行时间

类初始化块

1 次

第一次主动使用该类

实例初始化块

N 次

每次调用构造器

抽象类

见上面abstract关键字

接口

接口相当于一个彻底抽象的类,体现一种规范。接口中所有东西都使用public修饰(通常省略)。接口支持多继承。

接口定义

接口的定义如下:

[修饰符] interface 接口名 [extends 父接口1, 父接口2, ...] {  // 成员变量(常量,自动使用`public static final`修饰)  // 抽象方法:Java 8 后支持类方法、默认方法(带有方法体的抽象方法,与实例方法类似)。}

其中,修饰符只能为public接口名命名规范基本与类名系统,通常使用形容词来定义。

public interface MyInterface {  // 反编译后:  // public static final int MAX_WEIGHT = 100;  int MAX_WEIGHT = 100;  void test();  // 抽象方法  // Java 8 后的类方法  static void staticMethod() {    // ...  }  // Java 8 后的默认方法  default void defaultMethod() {    // ...  }}

使用接口

使用接口中成员变量类方法时,与调用类成员相似,即接口名.成员名

例如:

public class InterfaceTest {  public static void main(String[] args) {    System.out.println(MyInterface.MAX_WEIGHT); // 100    MyInterface.staticMethod();  }}

实现接口

子类要么重写接口中所有抽象方法,要么定义为抽象类。

实现接口的格式如下:

[修饰符] class 类名 implements 父接口1 [, 父接口2, ...] {  // 5大成员}

以实现上方的接口为例:

public class Test implements MyInterface {  @Override  public void test() {    // ...  }}

private方法本质是实例方法。

内部类

内部类是在类体中定义的类。

class 外部类 {  [修饰符] class 内部类 [extends 父类] [implements 接口] {    // ...  }}

内部类外部类的区别如下:

内部类外部类相比可使用staticprivateprotected修饰符。非静态内部类不能拥有静态成员(常量除外)。内部类可以直接访问外部类私有成员,但静态内部类不能访问外部类的非静态成员。

内部类的意义:当某个类的实例必须依附于另一个类存在时,可使用内部类。且内部类可以提供更好的封装(可使用private修饰)。

内部类生成的文件名格式为:外部类$内部类.class

内部类区分同名变量

class Foo {  int length = 20;  class Bar {    int length = 200;    void foo() {      int length = 2000;      System.out.println(length);            // 2000      System.out.println(this.length);       // 200      System.out.println(Foo.this.length);   // 20    }  }}

使用内部类

(1)在外部类中使用内部类

基本与使用其他类相同,需要注意的是静态成员不能使用非静态内部类创建实例

(2)在外部类的外面使用静态内部类

该内部类不能使用private修饰

class Foo {  public static class Bar {    public static void test() {      System.out.println("我来自Foo.Bar.test()");    }  }}public class Test {  public static void main(String[] args) {    Foo.Bar.test();  // 我来自Foo.Bar.test()  }}

(3)在外部类的外面使用非静态内部类 (不常见)

class Foo {  public class Bar {    public void test() {      System.out.println("非静态内部类");    }  }}public class Test{  public static void main(String[] args) {    Foo foo = new Foo();    Foo.Bar fb = foo.new Bar();    fb.test(); // 非静态内部类  }}

局部内部类

定义在方法中的内部类,不常用,略。

匿名内部类

匿名内部类指没有名字的类,无法复用。

匿名内部类的语法如下:

new 父类构造器(参数)|接口() {  // 除了构造器,其他都可以定义  // 但一般只实现抽象方法}

注意:

匿名内部类必须显式继承父类,或实现一个接口。匿名内部类不能是抽象类,因此必须实现抽象父类或接口中的所有抽象方法。

例如:

abstract class Foo {  public abstract void test();}public class Bar {  public static void main(String[] args) {    Foo foo = new Foo() {      @Override      public void test() {        System.out.println("匿名内部类");      }    };    foo.test();  // 匿名内部类  }}
枚举

枚举的定义格式如下:

[修饰符] enum 枚举名 {  // 第一行列出所有实例  // 可以定义 5 大成员}

修饰符只能为public

枚举类与普通类的区别:

枚举默认已经继承Enum类,无法继承其他类。枚举要么是final类,要么是abstract类。且 Java 会自动判断该类为final类还是abstract类。枚举要求在开头列出所有实例

枚举类默认拥有以下方法:

static Weekday[] values(): 返回所有枚举实例static Weekday valueOf(String):根据枚举名返回枚举实例String name():返回枚举实例的名称int ordinal():返回枚举实例的序号

例如:

enum Weekday {    SUN, MON, TUE, WED, THU, FRI, SAT; // 所有实例    Weekday() {        System.out.println("我来自构造器");    }    public void foo() {        System.out.println("我来自枚举中的foo方法");    }}public class EnumTest {    public static void main(String[] args) {        System.out.println(Weekday.WED);    // WED        System.out.println(Arrays.toString(Weekday.values())); // [SUN, MON, TUE, WED, THU, FRI, SAT]        Weekday d1 = Weekday.SUN;        System.out.println(d1.ordinal());   // 0        System.out.println(d1.name());      // SUN        d1.foo();  // 我来自枚举中的foo方法        Weekday d2 = Weekday.valueOf("TUE");    }}

枚举与switch

switch语句可以与枚举共同使用:

enum Weekday {    SUN, MON, TUE, WED, THU, FRI, SAT;    public void info() {        switch (this) {            case MON:            case TUE:            case WED:            case THU:            case FRI:                System.out.println("上班哦");                break;            case SAT:            case SUN:                System.out.println("放假哦");                break;        }    }}public class EnumTest {    public static void main(String[] args) {        Weekday day = Weekday.SUN;        day.info(); // 放假哦    }}

枚举类与构造器

枚举定义后本质为public static final的常量:

// 编译前:public enum Weekday {  SUN, MON, TUE, WED, THU, FRI, SAT;}// 编译后public final class Weekday extends Enum {  public static final Weekday SUN = new Weekday();  public static final Weekday MON = new Weekday();  public static final Weekday TUE = new Weekday();  public static final Weekday WED = new Weekday();  public static final Weekday THU = new Weekday();  public static final Weekday FRI = new Weekday();  public static final Weekday SAT = new Weekday();  private Weekday() {}}

当然,我们可以自己手动编写构造器,其使用方式与正常类相似:

enum Weekday {  SUN(false),  MON(true),  TUE(true),  WED(true),  THU(true),  FRI(true),  SAT(false);  private final boolean isWorkday;  Weekday(boolean isWorkday) {  // private 构造器    this.isWorkday = isWorkday;  }}

标签: #java且与或 #java中的switchthis