当前位置: 首页 > news >正文

Java基础:面向对象编程6

1 Java thissuper 关键字

1.1 this 关键字的作用

  • 作为引用变量,指向当前对象
/*** @package: com.yunyang.javabetter.oop.thisandsuper* @description: this用法之指向当前对象* @author: Yunyang* @date: 2024/10/15  10:24* @version:1.0**/
public class WithThisStudent {String name;int age;public WithThisStudent(String name, int age) {this.name = name;this.age = age;}public void out(){System.out.println(name+" " + age);}public static void main(String[] args) {WithThisStudent s1 = new WithThisStudent("zhangsan", 18);WithThisStudent s2 = new WithThisStudent("zhangsan", 16);s1.out();s2.out();}
}

运行结果:

zhangsan 18
zhangsan 16

分析:

  • 在构造方法中,this.xxx 指向的就是实例变量,而不再是参数本身了。
  • 如果参数名和实例变量名不同的话,就不必使用 this 关键字。
  • 调用当前类的方法
/*** @package: com.yunyang.javabetter.oop.thisandsuper* @description: this用法之调用当前类的方法* @author: Yunyang* @date: 2024/10/15  10:28* @version:1.0**/
public class InvokeCurrentClassMethod {void method1(){System.out.println("invoke method1");}void method2(){method1();}public static void main(String[] args) {new InvokeCurrentClassMethod().method2();}
}

运行结果

/*** @package: com.yunyang.javabetter.oop.thisandsuper* @description: this用法之调用当前类的方法* @author: Yunyang* @date: 2024/10/15  10:28* @version:1.0**/
public class InvokeCurrentClassMethod {void method1(){System.out.println("invoke method1");}void method2(){method1();System.out.println("invoke method2");}public static void main(String[] args) {new InvokeCurrentClassMethod().method2();}
}

分析:

  • 在一个类中使用 this 关键字来调用另外一个方法,如果没有使用的话,编译器会自动帮我们加上。
  • 在源代码中,method2() 在调用 method1() 的时候并没有使用 this 关键字,但通过反编译后的字节码可以看得到。
  • this() 可以调用当前类的构造方法
/*** @package: com.yunyang.javabetter.oop.thisandsuper* @description: this用法之调用当前类的构造方法* @author: Yunyang* @date: 2024/10/15  10:33* @version:1.0**/
public class InvokeConsructor {public InvokeConsructor() {System.out.println("hello");}public InvokeConsructor(int count){this();System.out.println(count);}public static void main(String[] args) {InvokeConsructor invokeConsructor = new InvokeConsructor(10);}
}

运行结果:

hello
10

分析:

  • 在有参构造方法 InvokeConstrutor(int count) 中,使用了 this() 来调用无参构造方法 InvokeConstrutor()。
/*** @package: com.yunyang.javabetter.oop.thisandsuper* @description: this用法之调用当前类的构造方法* @author: Yunyang* @date: 2024/10/15  10:38* @version:1.0**/
public class InvokeParamConstrutor {public InvokeParamConstrutor() {this(10); //this() 必须放在构造方法的第一行,否则就报错了System.out.println("hello");}public InvokeParamConstrutor(int count){System.out.println(count);}public static void main(String[] args) {InvokeParamConstrutor invokeParamConstrutor = new InvokeParamConstrutor();}
}

运行结果:

10
hello

分析:

  • 也可以在无参构造方法中使用 this() 并传递参数来调用有参构造方法;
  • 需要注意的是,this() 必须放在构造方法的第一行,否则就报错了。
  • this 可以作为参数在方法中传递
/*** @package: com.yunyang.javabetter.oop.thisandsuper* @description: this用法之作为参数在方法中传递* @author: Yunyang* @date: 2024/10/15  10:40* @version:1.0**/
public class ThisAsParam {void method1(ThisAsParam p){System.out.println(p);}void method2(){method1(this);}public static void main(String[] args) {ThisAsParam thisAsParam = new ThisAsParam();System.out.println(thisAsParam);thisAsParam.method2();}
}

运行结果:

com.yunyang.javabetter.oop.thisandsuper.ThisAsParam@35851384
com.yunyang.javabetter.oop.thisandsuper.ThisAsParam@35851384

分析:

method2() 调用了 method1(),并传递了参数 this,method1() 中打印了当前对象的字符串。 main() 方法中打印了 thisAsParam 对象的字符串。从输出结果中可以看得出来,两者是同一个对象。

  • this 可以作为参数在构造方法中传递
/*** @package: com.yunyang.javabetter.oop.thisandsuper* @description: this用法之作为参数在构造方法中传递* @author: Yunyang* @date: 2024/10/15  10:43* @version:1.0**/
public class ThisAsConstrutorParam {int count = 10;ThisAsConstrutorParam() {Data data = new Data(this);data.out();}public static void main(String[] args) {new ThisAsConstrutorParam();}
}class Data {ThisAsConstrutorParam param;Data(ThisAsConstrutorParam param) {this.param = param;}void out() {System.out.println(param.count);}
}

运行结果:

10

分析:

  • 在构造方法 ThisAsConstrutorParam() 中,我们使用 this 关键字作为参数传递给了 Data 对象,它其实指向的就是 new ThisAsConstrutorParam() 这个对象。
  • this 关键字也可以作为参数在构造方法中传递,它指向的是当前类的对象。当我们需要在多个类中使用一个对象的时候,这非常有用。
  • this 可以作为方法的返回值,返回当前类的对象
/*** @package: com.yunyang.javabetter.oop.thisandsuper* @description: this用法之作为方法的返回值* @author: Yunyang* @date: 2024/10/15  10:44* @version:1.0**/
public class ThisAsMethodResult {ThisAsMethodResult getThisAsMethodResult() {return this;}void out() {System.out.println("hello");}public static void main(String[] args) {new ThisAsMethodResult().getThisAsMethodResult().out();}
}

运行结果:

hello

分析:

  • getThisAsMethodResult() 方法返回了 this 关键字,指向的就是 new ThisAsMethodResult() 这个对象,所以可以紧接着调用 out() 方法——达到了链式调用的目的。
  • 需要注意的是,this 关键字作为方法的返回值的时候,方法的返回类型为类的类型。

1.2 super 关键字的作用

  • 指向父类对象
/*** @package: com.yunyang.javabetter.oop.thisandsuper* @description: super用法之指向父类对象* @author: Yunyang* @date: 2024/10/15  11:29* @version:1.0**/
public class ReferParentField {public static void main(String[] args) {new Dog().printColor();}
}class Animal {String color = "白色";
}class Dog extends Animal {String color = "黑色";void printColor() {System.out.println(color);System.out.println(super.color);}
}

运行结果:

黑色
白色

分析:

  • 如果父类和子类拥有同样名称的字段,super 关键字可以用来访问父类的同名字段。
  • 父类 Animal 中有一个名为 color 的字段,子类 Dog 中也有一个名为 color 的字段,子类的 printColor() 方法中,通过 super 关键字可以访问父类的 color。
  • 调用父类的方法
/*** @package: com.yunyang.javabetter.oop.thisandsuper* @description: super用法之调用父类的方法* @author: Yunyang* @date: 2024/10/15  14:06* @version:1.0**/
public class ReferParentMethod {public static void main(String[] args) {new Dog().work();}
}class Animal {void eat() {System.out.println("吃...");}
}class Dog extends Animal {@Overridevoid eat() {System.out.println("吃...");}void bark() {System.out.println("汪汪汪...");}void work() {super.eat();bark();}
}

运行结果:

...
汪汪汪...

分析:

  • 当子类和父类的方法名相同时,可以使用 super 关键字来调用父类的方法。换句话说,super 关键字可以用于方法重写时访问到父类的方法。
  • 父类 Animal 和子类 Dog 中都有一个名为 eat() 的方法,通过 super.eat() 可以访问到父类的 eat() 方法。
  • super() 可以调用父类的构造方法
/*** @package: com.yunyang.javabetter.oop.thisandsuper* @description: super用法之调用父类的构造方法* @author: Yunyang* @date: 2024/10/15  14:13* @version:1.0**/
public class ReferParentConstructor {public static void main(String[] args) {new Dog();}
}class Animal {Animal(){System.out.println("动物来了");}
}class Dog extends Animal {Dog() {super();System.out.println("狗狗来了");}
}

运行结果:

动物来了
狗狗来了

分析:

  • 子类 Dog 的构造方法中,第一行代码为 super(),它就是用来调用父类的构造方法的。
  • 在默认情况下,super() 是可以省略的,编译器会主动去调用父类的构造方法。也就是说,子类即使不使用 super() 主动调用父类的构造方法,父类的构造方法仍然会先执行。
/*** @package: com.yunyang.javabetter.oop.thisandsuper* @description: super用法之调用父类的有参构造函数* @author: Yunyang* @date: 2024/10/15  14:16* @version:1.0**/
class Person {int id;String name;Person(int id, String name) {this.id = id;this.name = name;}
}class Emp extends Person {float salary;Emp(int id, String name, float salary) {super(id, name);this.salary = salary;}void display() {System.out.println(id + " " + name + " " + salary);}
}public class CallParentParamConstrutor {public static void main(String[] args) {new Emp(1, "Zhangsan", 20000f).display();}
}

运行结果:

1 Zhangsan 20000.0

分析:

  • super() 也可以用来调用父类的有参构造方法,这样可以提高代码的可重用性;
  • Emp 类继承了 Person 类,也就继承了 id 和 name 字段,当在 Emp 中新增了 salary 字段后,构造方法中就可以使用 super(id, name) 来调用父类的有参构造方法。

1.3 小结

  • this 关键字:用于引用当前对象,调用当前类的方法,调用当前类的构造方法,作为参数传递,以及作为方法的返回值。
  • super 关键字:用于引用父类对象,调用父类的方法,以及调用父类的构造方法。

2 Java static 关键字

2.1 概述

static 关键字的作用可以用一句话来描述:“方便在没有创建对象的情况下进行调用,包括变量和方法”。也就是说,只要类被加载了,就可以通过类名进行访问。static 可以用来修饰类的成员变量和成员方法。

2.2 静态变量

  • 定义:如果在声明变量的时候使用了 static 关键字,那么这个变量就被称为静态变量。
  • 特点
    • 静态变量只在类加载的时候获取一次内存空间,这使得静态变量很节省内存空间。
    • 由于静态变量只会获取一次内存空间,所以任何对象对它的修改都会得到保留。
    • 静态变量属于一个类,所以不要通过对象引用来访问,而应该直接通过类名来访问,否则编译器会发出警告。

2.2 静态方法

  • 定义:如果方法上加了 static 关键字,那么它就是一个静态方法。
  • 特征
    • 静态方法属于这个类而不是这个类的对象。
    • 调用静态方法的时候不需要创建这个类的对象。
    • 静态方法可以访问静态变量。
  • 限制
    • 静态方法不能访问非静态变量和调用非静态方法。
  • 为什么 main 方法是静态的
    • 如果 main 方法不是静态的,就意味着 Java 虚拟机在执行的时候需要先创建一个对象才能调用 main 方法,而 main 方法作为程序的入口,创建一个额外的对象显得非常多余。
  • 示例
    • java.lang.Math 类的几乎所有方法都是静态的,可以直接通过类名来调用,不需要创建类的对象。

2.3 静态代码块

  • 定义:用一个 static 关键字,外加一个大括号括起来的代码被称为静态代码块。
  • 作用
    • 静态代码块通常用来初始化一些静态变量,它会优先于 main() 方法执行。
    • 静态代码块在初始化集合的时候非常有用。在实际的项目开发中,通常使用静态代码块来加载配置文件到内存当中。

2.4 静态内部类

  • 定义:Java 允许我们在一个类中声明一个内部类,它提供了一种令人信服的方式,允许我们只在一个地方使用一些变量,使代码更具有条理性和可读性。
  • 常见的内部类
    • 成员内部类
    • 局部内部类
    • 匿名内部类
    • 静态内部类
  • 静态内部类实现单例
    • 第一次加载 Singleton 类时并不会初始化 instance,只有第一次调用 getInstance() 方法时 Java 虚拟机才开始加载 SingletonHolder 并初始化 instance,这样不仅能确保线程安全,也能保证 Singleton 类的唯一性。
  • 注意
    • 静态内部类不能访问外部类的所有成员变量。
    • 静态内部类可以访问外部类的所有静态变量,包括私有静态变量。
    • 外部类不能声明为 static

2.5 示例代码

2.5.1 静态变量

/*** @package: com.yunyang.javabetter.oop.staticdemo* @description: 静态变量2* @author: Yunyang* @date: 2024/10/15  14:30* @version:1.0**/
public class Counter {static int count = 0;public Counter() {count++;System.out.println(count);}public static void main(String[] args) {Counter c1 = new Counter();Counter c2 = new Counter();Counter c3 = new Counter();}
}

运行结果:

1
2
3

分析:

  • 由于静态变量只会获取一次内存空间,所以任何对象对它的修改都会得到保留,所以每创建一个对象,count 的值就会加 1,所以最终的结果是 3。

2.5.2 静态方法

/*** @package: com.yunyang.javabetter.oop.staticdemo* @description: 静态方法* @author: Yunyang* @date: 2024/10/15  14:37* @version:1.0**/
public class StaticMethodStudent {String name;int age;static String school = "郑州大学";public StaticMethodStudent(String name, int age) {this.name = name;this.age = age;}static void change() {school = "河南大学";}void out() {System.out.println(name + " " + age + " " + school);}public static void main(String[] args) {StaticMethodStudent.change();StaticMethodStudent s1 = new StaticMethodStudent("沉默王二", 18);StaticMethodStudent s2 = new StaticMethodStudent("沉默王三", 16);s1.out();s2.out();}
}

运行结果:

沉默王二 18 河南大学
沉默王三 16 河南大学

分析:

  • change() 方法就是一个静态方法,所以它可以直接访问静态变量 school,把它的值更改为河南大学;并且,可以通过类名直接调用 change() 方法,就像 StaticMethodStudent.change() 这样。

2.5.3 静态代码块

/*** @package: com.yunyang.javabetter.oop.staticdemo* @description: 静态代码块* @author: Yunyang* @date: 2024/10/15  14:40* @version:1.0**/
public class StaticBlock {static {System.out.println("静态代码块");}public static void main(String[] args) {System.out.println("main 方法");}
}

运行结果:

静态代码块
main 方法

分析:

  • 静态代码块通常用来初始化一些静态变量,它会优先于 main() 方法执行。
/*** @package: com.yunyang.javabetter.oop.staticdemo* @description: 静态代码块* @author: Yunyang* @date: 2024/10/15  14:41* @version:1.0**/
public class StaticBlockNoMain {static {System.out.println("静态代码块,没有 main");}
}

运行结果:

D:\Gitee\JavaKnowledgeBase>java StaticBlockNoMain
错误: 找不到或无法加载主类 StaticBlockNoMain

分析:

  • 在命令行中执行 java StaticBlockNoMain 的时候,会抛出 NoClassDefFoundError 的错误;
  • Java 7 开始没有 main() 方法的 Java 类无法执行。
/*** @package: com.yunyang.javabetter.oop.staticdemo* @description: 静态代码块* @author: Yunyang* @date: 2024/10/15  14:42* @version:1.0**/
public class StaticBlockDemo {public static List<String> writes = new ArrayList<>();static {writes.add("沉默王二");writes.add("沉默王三");writes.add("沉默王四");System.out.println("第一块");}static {writes.add("沉默王五");writes.add("沉默王六");System.out.println("第二块");}public static void main(String[] args) {}
}

运行结果:

第一块
第二块

分析:

  • writes 是一个静态的 ArrayList,所以不太可能在声明的时候完成初始化,因此需要在静态代码块中完成初始化

2.5.4 静态内部类实现单例

/*** @package: com.yunyang.javabetter.oop.staticdemo* @description: 静态内部类* @author: Yunyang* @date: 2024/10/15  14:44* @version:1.0**/
public class Singleton {private Singleton(){}private static class SingletonHolder{public static final Singleton insstance = new Singleton();}public static Singleton getInstance(){return SingletonHolder.insstance;}
}

分析:

  • 第一次加载 Singleton 类时并不会初始化 instance,只有第一次调用 getInstance() 方法时 Java 虚拟机才开始加载 SingletonHolder 并初始化 instance,这样不仅能确保线程安全,也能保证 Singleton 类的唯一性。

2.6 小结

static 关键字在 Java 中用于修饰类的成员变量和方法,使得它们可以在没有创建对象的情况下通过类名直接访问。静态变量和静态方法在类加载时初始化,静态代码块用于初始化静态变量,静态内部类可以用于实现单例模式。合理使用 static 关键字可以提高代码的可读性和性能。

3 Java final 关键字

3.1 final 变量

  • 定义:被 final 修饰的变量无法重新赋值。换句话说,final 变量一旦初始化,就无法更改。
  • 特点
    • final 修饰的成员变量必须有一个默认值,否则编译器将会提醒没有初始化。
    • finalstatic 一起修饰的成员变量叫做常量,常量名必须全部大写。
    • final 关键字来修饰参数,它意味着参数在方法体内不能被再修改。如果尝试去修改它的话,编译器会提示错误。

3.2 final 方法

  • 定义:被 final 修饰的方法不能被重写。如果我们在设计一个类的时候,认为某些方法不应该被重写,就应该把它设计成 final 的。
  • 示例
    • Thread 类就是一个例子,它本身不是 final 的,这意味着我们可以扩展它,但它的 isAlive() 方法是 final 的。该方法是一个本地(native)方法,用于确认线程是否处于活跃状态。而本地方法是由操作系统决定的,因此重写该方法并不容易实现。
  • 区别
    • 一个类是 final 的,和一个类不是 final,但它所有的方法都是 final 的,它们之间有什么区别?
      • 前者不能被继承,也就是说方法无法被重写;后者呢,可以被继承,然后追加一些非 final 的方法。

3.3 final

  • 定义:如果一个类使用了 final 关键字修饰,那么它就无法被继承。
  • 示例
    • String 类就是一个 final 类。
  • 原因
    • 为了实现字符串常量池String 类被设计成 final,可以确保字符串常量池中的字符串对象不可变,从而提高性能和安全性。
    • 为了线程安全String 对象的不可变性使得它在多线程环境下是线程安全的。
    • 为了 HashCode 的不可变性String 对象的不可变性确保了 hashCode 方法的返回值在对象创建后不会改变,这对于使用 String 作为 HashMap 的键非常重要。
  • 注意
    • 任何尝试从 final 类继承的行为将会引发编译错误。
    • 类是 final 的,并不意味着该类的对象是不可变的。
    • 把一个类设计成 final 的,有其安全方面的考虑,但不应该故意为之,因为把一个类定义成 final 的,意味着它没办法继承,假如这个类的一些方法存在一些问题的话,我们就无法通过重写的方式去修复它。

3.4 示例代码

3.4.1 final 变量

public class FinalVariableExample {final int finalVar = 10;static final int CONSTANT_VAR = 20;public void method(final int param) {// param = 30; // 编译错误,final 参数不能被修改System.out.println("Final variable: " + finalVar);System.out.println("Constant variable: " + CONSTANT_VAR);}public static void main(String[] args) {FinalVariableExample example = new FinalVariableExample();example.method(40);}
}

3.4.2 final 方法

public class FinalMethodExample {public final void finalMethod() {System.out.println("This is a final method");}public static void main(String[] args) {FinalMethodExample example = new FinalMethodExample();example.finalMethod();}
}class SubClass extends FinalMethodExample {// 编译错误,无法重写 final 方法// public void finalMethod() {//     System.out.println("Overriding final method");// }
}

3.4.3 final

public final class FinalClassExample {public void method() {System.out.println("This is a method in a final class");}public static void main(String[] args) {FinalClassExample example = new FinalClassExample();example.method();}
}// 编译错误,无法继承 final 类
// class SubClass extends FinalClassExample {
// }

3.5 小结

final 关键字在 Java 中用于修饰变量、方法和类,具有以下特点:

  • final 变量:一旦初始化后无法更改。
  • final 方法:不能被重写。
  • final:不能被继承。

4 Java instanceof 关键字

4.1 作用

instanceof 关键字用于判断一个对象是否符合指定的类型,结果要么是 true,要么是 false

4.2 用法

(object) instanceof (type)

4.3 示例

在反序列化的时候,instanceof 操作符还是蛮常用的,因为这时候我们不太确定对象是否属于指定的类型,如果不进行判断的话,就容易抛出 ClassCastException 异常。

public class InstanceOfExample {public static void main(String[] args) {Object obj = "Hello, World!";if (obj instanceof String) {System.out.println("obj is an instance of String");} else {System.out.println("obj is not an instance of String");}}
}

4.4 继承与 instanceof

Java 是一门面向对象的编程语言,也就意味着除了基本数据类型,所有的类都会隐式继承 Object 类。因此,任何对象都可以被视为 Object 的实例。

public class InstanceOfExample2 {public static void main(String[] args) {Object obj = new ArrayList<>();if (obj instanceof List) {System.out.println("obj is an instance of List");}if (obj instanceof ArrayList) {System.out.println("obj is an instance of ArrayList");}if (obj instanceof Object) {System.out.println("obj is an instance of Object");}}
}

4.5 nullinstanceof

对于 null 来说,instanceof 的结果为 false。因为所有的对象都可以为 null,所以也不好确定 null 到底属于哪一个类。

public class InstanceOfExample3 {public static void main(String[] args) {Object obj = null;if (obj instanceof String) {System.out.println("obj is an instance of String");} else {System.out.println("obj is not an instance of String");}}
}

4.6 小结

instanceof 关键字在 Java 中用于判断一个对象是否符合指定的类型,结果要么是 true,要么是 false。它在类型检查和避免 ClassCastException 异常时非常有用。需要注意的是,对于 null 对象,instanceof 的结果总是 false

5 思维导图

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

在这里插入图片描述

6 参考链接

  1. 详解Java this与super关键字的用法与区别
  2. 详解 Java static 关键字的作用:静态变量、静态方法、静态代码块、静态内部类
  3. 一文彻底搞懂 Java final 关键字
  4. 掌握 Java instanceof关键字

http://www.mrgr.cn/news/51104.html

相关文章:

  • Python连接Oracle
  • 前端常用的库有哪些?
  • 单片机(学习)2024.10.15
  • 2024.10 学习笔记
  • 机器学习(MachineLearning)(8)——模型评估与优化
  • ES6新增promise(异步编程新解决方案)如何封装ajax?
  • Springboot开发——IDEA高版本中如何创建JDK8的项目
  • 2024年10月16日历史上的今天大事件早读
  • 嵌入式SoPC最全面试题及参考答案
  • 跨域问题和前端攻击
  • 《Windows PE》6.4.1 无 DLL远程注入
  • 网页前端开发之HTML入门
  • 大商创(移动端) -- day02
  • 【功能介绍】麒麟2403支持设置任务栏上的图标“从不合并”啦!
  • 上海亚商投顾:沪指险守3200 全市场下跌个股超4500只
  • 冷板凳30年,离职时75岁!看完老爷子的简历,我失眠了
  • 开通实时计算Flink版
  • 一款.NET开源的i茅台自动预约小助手
  • 【报错处理】MR/Spark 使用 BulkLoad 方式传输到 HBase 发生报错: NullPointerException
  • 高效的并行处理:使用 Python 的 `multiprocessing` 库管理进程