5-Java 面向对象基础2

5.6 this 关键字

对象创建的过程和 this 的本质

构造方法是创建 Java 对象的重要途径,通过 new 关键字调用构造器时,构造器也确实返回该类的对象,但这个对象并不是完全由构造器负责创建。创建一个对象分为如下四步:

  1. 分配对象空间,并将对象成员变量初始化为 0 或空
  2. 执行属性值的显式初始化
  3. 执行构造方法
  4. 返回对象的地址给相关的变量

this 的本质就是“创建好的对象的地址”!由于在构造方法调用前,对象已经创建。因此,在构造方法中也可以使用 this 代表“当前对象” 。

this 最常的用法

  1. 在程序中产生二义性之处,应使用 this 来指明当前对象;普通方法中,this 总是指向调用该方法的对象。构造方法中,this 总是指向正要初始化的对象。
  2. 使用 this 关键字调用重载的构造方法,避免相同的初始化代码。但只能在构造方法中用,并且必须位于构造方法的第一句。
  3. this 不能用于 static 方法中,因为 static 是放在类信息中,而不是对象。

示例

public class TestThis {
  int a;
  int b;
  int c;
  
  TestThis(int a, int b) {
    this.a = a;
    this.b = b;
  }
  
  TestThis(int a, int b, int c) {
    this(a, b); // 构造器的调用只能放在第一句
    this.c = c;
  }
  
  void sing() {
  }
  
  void eat() {
    this.sing(); // 这里的this可写可不写
    System.out.println("Eating!");
  }
  
  public static void main(String[] args) {
    TestThis tt = new TestThis(2, 3);
    tt.eat();
  }
  
}

5.7 static 关键字

在类中,用 static 声明的成员变量为静态成员变量,也称为类变量类变量的生命周期和类相同,在整个应用程序执行期间都有效。它有如下特点:

  1. 为该类的公用变量,属于类,被该类的所有实例共享,在类被载入时被显式初始化。
  2. 对于该类的所有对象来说,static 成员变量只有一份。被该类的所有对象共享!!
  3. 一般用“类名.类属性/方法”来调用;也可以通过对象引用或类名(不需要实例化)访问静态成员。
  4. 在 static 方法中不可直接访问非 static 的成员。

核心要点:

static 修饰的成员变量和方法,从属于类。

普通变量和方法从属于对象的。

  • static 关键字的使用

    /**
     * static 关键字的使用
     * @author IZJ
     *
     */
    public class User2 {
        int id;
        String name;
        String pwd;
        static String school = "GDUFS";
    
        public User2(int id, String name) {
            this.id = id;
            this.name = name;
        }
    
        public void login() {
            printSchool();
            System.out.println(school);
            System.out.println("登录:" + this.name);
        }
    
        public static void printSchool() {
            // login(); //调用非静态成员,编译报错
            System.out.println(school);
        }
    
        public static void main(String[] args) {
            User2 u = new User2(1, "ZJax");
            User2.printSchool();
            User2.school = "TUNA";
            User2.printSchool();
        }
    }
    

理解:类好比就是一张造汽车的图纸,而对象就是造出来的汽车,有图纸不一定有汽车,而有汽车一定有对应的图纸。因此,类不能直接调用对象的成员变量和方法(即非 static 修饰的成员变量和方法),因为对象不一定存在,即汽车不一定造出来了;而对象可以调用类的各种变量和方法,因为汽车是根据图纸造出来的。

img

5.8 静态初始化块

构造方法用于对象的初始化!

静态初始化块,用于类的初始化!

在静态初始化块中不能直接访问非 static 成员。

静态初始化块执行顺序(涉及到继承):

  1. 上溯到 Object 类,先执行 Object 的静态初始化块,再向下执行子类的静态初始化块,直到我们的类的静态初始化块为止。也就是父类的静态初始化块优先。
  2. 构造方法执行顺序和上面顺序一样!
/**
 * 静态初始化块
 * @author IZJ
 *
 */
public class User3 {
    int id;
    String name;
    String pwd;
    static String university;
    static {
        System.out.println("执行类的初始化工作");
        university = "TUNA";
        printUniversity();
    }  
    public static void printUniversity(){
        System.out.println(university);
    }  
    public static void main(String[] args) {
        User3  u3 = new User3();
    }
}

5.9 参数传值机制

Java 中,方法中所有参数都是“值传递”。

  • 基本数据类型参数的传值

    传递的是值而不是地址,因此传递过来的值的改变不会影响原来的变量的值的变化。

  • 引用类型参数的传值

    传递的是“对象的地址”。因此,调用传递过来的值修改其内容会直接影响原来变量的改变。

/**
 * 测试参数传递
 * @author IZJ
 *
 */
public class User4 {
    int id;
    String name;
    String pwd;

    public User4(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public void testParameterTransfer01(User4 u) {
        u.name = "IZJ";
    }

    public void testParameterTransfer02(User4 u){
        u = new User4(2, "ZJ"); // 参数u的值改变,并不影响 main 方法中的 u1 的地址
    }

    public static void main(String[] args) {
        User4 u1 = new User4(1, "ZJax");
        u1.testParameterTransfer01(u1); // 传递了 u1 的地址
        System.out.println(u1.name);
        u1.testParameterTransfer02(u1);
        System.out.println(u1.name);
    }
}

5.10 包

包机制是 Java 中管理类的重要手段。 开发中,我们会遇到大量同名的类,通过包我们很容易对解决类重名的问题,也可以实现对类的有效管理。 包对于类,相当于文件夹对于文件的作用

package

我们通过 package 实现对类的管理,package 的使用有两个要点:

  1. 通常是类的第一句非注释性语句。
  2. 包名:域名倒着写即可,再加上模块名,便于内部管理类。
  • package的命名举例

    com.sun.test;
    com.oracle.test;
    cn.sxt.gao.test;
    cn.sxt.gao.view;
    cn.sxt.gao.view.model;
    
  • 注意事项:

    1. 写项目时都要加包,不要使用默认包。

    2. com.gao 和 com.gao.car,这两个包没有包含关系,是两个完全独立的包。只是逻辑上看起来后者是前者的一部分。

    3. 创建包,Idea 中 src 文件夹上右键 New –> package

JDK 中的主要包

Java 中的常用包说明
java.lang包含一些 Java 语言的核心类,如 String、Math、Integer、System 和 Thread,提供常用功能。
java.awt包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。
java.net包含执行与网络相关的操作的类。
java.io包含能提供多种输入/输出功能的类。
java.util包含一些实用工具类,如定义系统特性、使用与日期日历相关的函数。

导入 import

如果我们要使用其他包的类,需要使用 import 导入,从而可以在本类中直接通过类名来调用,否则就需要书写类的完整包名和类名。import 后,便于编写代码,提高可维护性。

  • 示例

    package top.zjax.oo;
    
    public class User {
    }
    
    package top.zjax.test;
    
    import top.zjax.oo.User;
    
    public class Test {
        public static void main(String[] args) {
            User user = new User();
        }
    }
    

注意要点:

  1. Java 会默认导入 java.lang 包下所有的类,因此这些类我们可以直接使用。

  2. 如果导入两个同名的类,只能用包名 + 类名来显示调用相关类:

    java.util.Date date  = new  java.util.Date();
    
  3. import java.util.*;会导入该目录下的所有类,这样会降低编译速度,但不会降低运行速度。

  • 导入同名类的处理

    import top.zjax.oo.User;
    import java.sql.Date;
    
    public class Test {
        public static void main(String[] args) {
            User user = new User();
    
            // 这里指的是java.sql.Date
            Date now;
    
            // java.util.Date 因为和 java.sql.Date 类同名,需要完整路径
            java.util.Date date = new java.util.Date();
        }
    }
    

静态导入

静态导入(static import)是在 JDK1.5 新增加的功能,其作用是用于导入指定类的静态属性,这样我们可以直接使用静态属性。

  • 示例

    package cn.sxt;
    // 以下两种静态导入的方式二选一即可
    import static java.lang.Math.*; // 导入 Math 类的所有静态属性
    import static java.lang.Math.PI; // 导入 Math 类的静态属性 PI
    
    public class Test2 {
        public static void main(String[] args) {
            System.out.println(PI);
            System.out.println(random());
        }
    }