第3章 面向对象(上)


学习目标

1. 面向对象的思想

面向对象是相对于面向过程来讲的,是一种符合人类思维习惯的编程思想

面向对象方法学认为,客观世界由对象组成。任何事物都是对象,每个对象都有自己的内部状态(特性、属性)和运动规律(方法、函数),不同对象彼此间通过消息相互作用、相互联系,从而构成了我们所要分析和构造的系统。系统中每个对象都属于一个特定的对象类。类是对具有相同属性和行为(方法)的一组相似对象的抽象定义。

客观世界 = Σ 对象

对象 = 属性s + 方法s

不同类之间相互作用、相互联系

类和对象:

面向对象是把构成问题的事物按照一定规则划分为多个独立的对象,然后通过调用对象的方法来解决问题。

(1) 封装性

封装是面向对象的核心思想,指访问的封装性。它有两层含义:

(2) 继承性

继承性主要描述的是类与类之间的关系,通过继承,可以在原有类的基础上,对原有类的功能进行扩展

(3) 多态性

多态性是指在一个类中同名方法(但参数类型、个数或顺序不同)或子类覆盖父类同名方法而执行不同的行为。

Java多态实现的三种形式,包括方法重载、方法重写和接口。

2. 类与对象

2.1 类的定义

类是对象的抽象,用于描述一组对象的共同特征和行为。

类中可以定义成员变量和成员方法,其中:

类 = 成员变量s + 成员方法s

class 类名{
   成员变量s;
   成员方法s;
}
package cn.xj.ch03.ex00;
public class Student {
    // 1.属性 -- 特征
    String 姓名;
    int 年龄;
    String 性别;

    // 2.方法--行为
    public void study(){
        System.out.println(姓名+"正在学习");
    }
    public void play() {
        System.out.println(姓名 + "正在玩游戏");
    }
}

局部变量与成员变量的不同

在Java中,定义在类中的变量被称为成员变量,定义在方法中的变量被称为局部变量。

----如果在某一个方法中定义的局部变量与成员变量同名,这种情况是允许的。此时,在方法中通过变量名访问到的是局部变量,而并非成员变量。

package cn.xj.ch03.ex00;
public class Example1_xj {
    public static void main(String[] args) {
        System.out.println("【例题】局部变量与成员变量同名,方法中通过变量名访问到的是局部变量  (许杰)");
        Student1 stu = new Student1();         // 创建第一个Student对象
        stu.read();                          // 调用对象的方法
    }
}

class Student1 {
    String 姓名;

    public void read(){
        姓名 = "张三";
        System.out.println(姓名+"正在看书。");
    }
}
图1 局部变量与成员变量同名
package cn.xj.ch03.ex00;
public class Example2_xj {
    public static void main(String[] args) {
        System.out.println("【例题】局部变量与成员变量同名,方法中通过变量名访问到的是局部变量  (许杰)");
        Student2 stu = new Student2();         // 创建第一个Student对象
        stu.read();                          // 调用对象的方法
    }
}

class Student2 {
    int 年龄 = 30;

    public void read(){
        int 年龄 = 50;
        System.out.println("大家好,我" +年龄+"岁了,我在看书!");
    }
}
图2 局部变量与成员变量同名

2.2 对象的创建与使用

// 声明对象1
类名 对象名称 = null;

// 声明对象2
类名 对象名称;

// 创建对象
对象名称 = new 类名();

// 声明并创建对象
类名 对象名称 = new 类名();

Java把内存划分成两种: 一种是栈内存,一种是堆内存。

图3 Java的栈内存和堆内存
package cn.xj.ch03.ex01;
public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例题01】对象的创建与使用 (许杰)");
        Student stu1 = new Student();         // 创建第一个Student对象
        Student stu2 = new Student();         // 创建第二个Student对象
        stu1.姓名 = "小明";                     // 为stu1对象的 姓名 属性赋值
        stu1.年龄 = 18;
        stu1.read();                          // 调用对象的方法
        stu2.姓名 = "许杰";
        stu2.年龄 = 60;
        stu2.read();
    }
}
class Student {
    String 姓名;                            // 声明姓名属性
    int 年龄;                               // 声明年龄属性

    void read() {
        System.out.println("大家好,我是" + 姓名 +",年龄" + 年龄);
    }
}
图4 对象的创建与使用

2.3 对象的引用传递

属于引用数据类型,引用数据类型就是指内存空间可以同时被多个栈内存引用

package cn.xj.ch03.ex02;
public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例02】对象的引用传递 (许杰)");
        Student stu1 = new Student();  //创建stu1对象并实例化stu1.
        stu1.name ="张三";
        stu1.age = 18;
        stu1.read();

        System.out.println(" -----stu2 = stu1; 之后-------- ");
        Student stu2= null; //创建stu2对象,但不对其进行实例化建stu2对象,但不对其进行实例化
        stu2 = stu1;        //把对象stu1赋给对象stu2, 即 stu2引用stu1----stu1和stu2同时指向同一堆内存
        stu2.name ="许杰";
        stu2.age = 60;
        stu1.read();
        stu2.read();
    }
}

class Student {
    String name;                            // 声明姓名属性
    int age;                                // 声明年龄属性

    void read() {
        System.out.println("大家好,我是" + name + ",年龄" + age);
    }
}
图5 对象的引用传递
图6 对象的引用示意

注意:一个栈内存空间只能指向一个堆内存空间,如果想要再指向其他堆内存空间,就必须先断开已有的指向才能分配新的指向。

2.4 访问控制权限

在Java中,针对类、成员方法和属性,Java提供了4种访问控制权限,分别是private、default、protected和public

图7 访问级别(范围)的顺序

访问控制权限的访问范

访问范围 private(私有) default(缺省、默认) protected(受保护) public(公开)
同一类中
同一包中的类
不同包的子类
全局范围

(1) 同一类中

package cn.xj.ch03.ex02_;
public class Student {
    private int 年龄 = 16;    //私有的
    int 体重 = 56;            //默认的
    protected String 住址 = "文华街125号";    //受保护的
    public String 姓名 = "许杰";           //公共的

    // 本类中可以访问 private、缺省/默认、protected、public的成员属性、成员方法
    public void show() {
        System.out.println("--- public修饰的方法中 ---");
        System.out.println("年龄="+年龄);
        System.out.println("体重="+体重);
        System.out.println("住址="+住址);
        System.out.println("姓名="+姓名);
    }

    void info() {
        System.out.println("--- 缺省/默认方法中 ---");
        System.out.println("  年龄 = "+年龄);
        System.out.println("  体重 = "+体重);
        System.out.println("  住址 = "+住址);
        System.out.println("  姓名 = "+姓名);
    }

    protected void info2() {
        System.out.println("--- protected修饰的方法中 ---");
        System.out.println("  年龄 = "+年龄);
        System.out.println("  体重 = "+体重);
        System.out.println("  住址 = "+住址);
        System.out.println("  姓名 = "+姓名);
    }

    private void me() {
        System.out.println("--- private修饰的方法中 ---");
        System.out.println("me  年龄 = "+年龄);
        System.out.println("me  体重 = "+体重);
        System.out.println("me  住址 = "+住址);
        System.out.println("me  姓名 = "+姓名);
    }

    public static void main(String[] args) {
        System.out.println("【例】访问控制权限 ---- 同一类中 (许杰)");
        Student stu = new Student();
        stu.show();     // public
        stu.info();     // 缺省
        stu.info2();    // protected
        stu.me();       // private
        System.out.println(stu.姓名); // public
        System.out.println(stu.住址); // protected
        System.out.println(stu.体重); // 默认
        System.out.println(stu.年龄); // private
    }
}
图8 访问级别--同一类中

(2) 同一包下的其他类

package cn.xj.ch03.ex02_;
public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例题】访问修饰符--同一包下的其他类 (许杰)");
        Student stu = new Student();
        stu.show();     // public
        stu.info();     // 缺省
        stu.info2();    // protected
        //stu.me();       // private me()' 在 'cn.xj.ch03.ex02_.Student' 中具有 private 访问权
        System.out.println(stu.姓名); // public
        System.out.println(stu.住址); // protected
        System.out.println(stu.体重); // 默认
        // System.out.println(stu.年龄); // '年龄' 在 'cn.xj.ch03.ex02_.Student' 中具有 private 访问权限
        System.out.println(stu.姓名); // public
    }
}
图9 访问级别--同一包下的其他类

(3) 不同包下的其他类

package cn.xj.ch03.ex02__;
import cn.xj.ch03.ex02_.Student;

/**
* 1. private --私有的,只能在本类中访问
* 2. 缺省 default --默认的,只能在本包中访问
* 3. protected --除了本包可以使用外,在其他包的子类里可以访问
* 4.public --任意包,任意类
* 注意点:
*   1.局部变量是没有访问权限的
*   2. private还可以修饰类内部类--外部类有两种修饰public和默认
**/
public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例题】访问修饰符--不同包下的其他类 (许杰)");
        // 在其他包的其他类中,只有public修饰的才可以被访问到!
        Student stu = new Student();        stu.show();     // public
        //stu.info();     // 缺省 'info() 在cn.xj.ch03.ex02_.Student 中不为 public。无法从外部软件包访问
        //stu.info2();    // protected info2() 在cn.xj.ch03.ex02_.Student 中具有 protected 访问权限
        //stu.me();     // private me()' 在 'cn.xj.ch03.ex02_.Student' 中具有 private 访问权
        stu.show();
        // stu.info();  // info()' 在 'cn.xj.ch03.ex02_.Student' 中不为 public。无法从外部软件包访问
        System.out.println(stu.姓名);
        //System.out.println(stu.年龄);   //'年龄' 在 'cn.xj.ch03.ex02_.Student' 中具有 private 访问权限
        //System.out.println(stu.体重);   //'体重' 在 'cn.xj.ch03.ex02_.Student' 中不为 public。无法从外部软件包访问
        //System.out.println(stu.住址);   //'住址' 在 'cn.xj.ch03.ex02_.Student' 中具有 protected 访问权限
    }
}package cn.xj.ch03.ex02__;
import cn.xj.ch03.ex02_.Student;

/**
* 1. private --私有的,只能在本类中访问
* 2. 缺省 default --默认的,只能在本包中访问
* 3. protected --除了本包可以使用外,在其他包的子类里可以访问
* 4. public --任意包,任意类
* 注意点:
*   1. 局部变量是没有访问权限的修饰
*   2. private还可以修饰类内部类--外部类有两种修饰public和默认
**/
public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例题】访问修饰符--不同包下的其他类 (许杰)");
        // 在其他包的其他类中,只有public修饰的才可以被访问到!
        Student stu = new Student();        stu.show();     // public
        //stu.info();     // 缺省 'info() 在cn.xj.ch03.ex02_.Student 中不为 public。无法从外部软件包访问
        //stu.info2();    // protected info2() 在cn.xj.ch03.ex02_.Student 中具有 protected 访问权限
        //stu.me();     // private me()' 在 'cn.xj.ch03.ex02_.Student' 中具有 private 访问权
        stu.show();
        // stu.info();  // info()' 在 'cn.xj.ch03.ex02_.Student' 中不为 public。无法从外部软件包访问
        System.out.println(stu.姓名);
        //System.out.println(stu.年龄);   //'年龄' 在 'cn.xj.ch03.ex02_.Student' 中具有 private 访问权限
        //System.out.println(stu.体重);   //'体重' 在 'cn.xj.ch03.ex02_.Student' 中不为 public。无法从外部软件包访问
        //System.out.println(stu.住址);   //'住址' 在 'cn.xj.ch03.ex02_.Student' 中具有 protected 访问权限
    }
}
图10 访问级别--不同包下的其他类

(4) 不同包下的其他类----包下的子包

package cn.xj.ch03.ex02_.sub;
import cn.xj.ch03.ex02_.Student;
public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例题】访问修饰符--不同包(含子包)下的其他类 (许杰)");
        // 在其他包(含子包)的其他类中,只有public修饰的才可以被访问到!
        Student stu = new Student();
        stu.show();
        // stu.info();  // info()' 在 'cn.xj.ch03.ex02_.Student' 中不为 public。无法从外部软件包访问
        System.out.println(stu.姓名);
        //System.out.println(stu.年龄);   //'年龄' 在 'cn.xj.ch03.ex02_.Student' 中具有 private 访问权限
        //System.out.println(stu.体重);   //'体重' 在 'cn.xj.ch03.ex02_.Student' 中不为 public。无法从外部软件包访问
        //System.out.println(stu.住址);   //'住址' 在 'cn.xj.ch03.ex02_.Student' 中具有 protected 访问权限
    }
}
图11 访问级别--不同包(子包)下的其他类

(5) 子类

package cn.xj.ch03.ex02__;
import cn.xj.ch03.ex02_.Student;

public class XiaoMing extends Student {
    public static void main(String[] args) {
        System.out.println("【例题】访问修饰符--子类中可访问protected/public修饰符的属性和方法 (许杰)");
        XiaoMing xm = new XiaoMing();
        // xm.info(); //info()' 在 'cn.xj.ch03.ex02_.Student' 中不为 public。无法从外部软件包访问
        // xm.me();  //'me()' 在 'cn.xj.ch03.ex02_.Student' 中具有 private 访问权限
        xm.show();
        xm.info2();
        System.out.println(xm.姓名);
        System.out.println(xm.住址);
        // System.out.println(xm.年龄); // '年龄' 在 'cn.xj.ch03.ex02_.Student' 中具有 private 访问权限
        // System.out.println(xm.体重);  // '体重' 在 'cn.xj.ch03.ex02_.Student' 中不为 public。无法从外部软件包访问
    }
}
图12 访问级别--子类可访问protected/public修饰符的属性和方法

访问控制权限使用注意点

package cn.xj.ch03.ex02__;
/**
 * 注意点:
 *   1. 局部变量是没有访问权限的,局部变量只在其作用域内起作用,不可能被其他类访问到
 *   2. private还可以修饰类内部类,内部类可用4种修饰:public、默认、protected、private
 *   3. 外部类只有两种修饰:public和默认
 **/
public class Test {
    void cc() {               //默认访问权限,能在本包范围内使用
        public int aa;        //错误,局部变量没有访问权限控制
        protected boolean bb; //错误,局部变量没有访问权限控制
        System.out.println("包访问权限");
    }
    //private权限的内部类,即这是私有的内部类,只能在本类使用
    private class InnerClass {
    }
    protected class InnerClass2 {
    }
    class InnerClass3 {
    }
    public class InnerClass4 {
    }
}

private class Class2 {
}

protected class Class3 {
}

Java程序的文件名

3. 封装性

封装是面向对象思想中的三个非常重要的概念(封装、继承、多态)之一。

3.1 为什么要封装

在Java面向对象的思想中,封装是指一种将类的实现细节包装、隐藏起来的方法。封装可以被认为是一个保护屏障,防止本类的代码和数据被外部类定义的代码随机访问。

package cn.xj.ch03.ex03;
public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例03】未封装 -- 成员变量(属性)没有修饰,类外部随意访问和修改 (许杰)");
        Student stu = new Student();    // 创建学生对象
        stu.name = "张三";                  // 为对象的name属性赋值
        stu.age = -18;                      // 为对象的age属性赋值,年龄负数
        stu.read();                           // 调用对象的方法
    }
}

class Student {
    String name;                            // 声明姓名属性
    int age;                                // 声明年龄属性

    void read() {
        System.out.println("大家好,我是" + name + ",年龄" + age);
    }
}
图13 未封装

3.2 如何实现封装

类的封装是指将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象的内部信息,而是通过该类提供的方法实现对内部信息的操作访问。

类的封装 = private属性 + public getter/setter

package cn.xj.ch03.ex04;

public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例04】封装:private属性+public setter/getter (许杰)");
        Student stu = new Student();        // 创建学生对象
        stu.set姓名("许杰");                // 为对象的name属性赋值
        stu.set年龄(-60);                    // 为对象的age属性赋值
        stu.read();                         // 调用对象的方法
        System.out.println(stu.toString());
    }
}

class Student{
    private String 姓名;                           // 声明姓名属性
    private int 年龄;                              // 声明年龄属性

    public String get姓名() {
        return 姓名;
    }

    public void set姓名(String 姓名) {
        this.姓名 = 姓名;
    }

    public int get年龄() {
        return 年龄;
    }

    public void set年龄(int 年龄) {
        if(年龄 < 0){
            System.out.println("您输入的年龄有误!");
        } else {
            this.年龄 = 年龄;
        }
    }

    @Override
    public String toString() {
        return "Student{" +
                "姓名='" + 姓名 + '\'' +
                ", 年龄=" + 年龄 +
                '}';
    }

    public void read() {
        System.out.println("大家好,我是"+姓名+",年龄"+年龄);
    }
}
图14 封装

4. 构造方法

4.1 定义构造方法

构造方法是一个特殊的成员方法。

package cn.xj.ch03.ex05;

public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例05】无参构造方法 (许杰)");
        System.out.println("声明对象...");
        Student stu = null;            //声明对象
        System.out.println("实例化对象...");
        stu = new Student();           //实例化对象
    }
}

class Student {
    public Student() {
        System.out.println("  调用了无参构造方法");
    }
}
图15 无参构造方法
package cn.xj.ch03.ex06;
class Student{
    private String 姓名;
    private int 年龄;
    public Student(String n, int a) {
        姓名 = n;
        年龄 = a;
        System.out.println("调用了有参构造方法");
    }
    public void read(){
        System.out.println("  我是:"+姓名+",年龄:"+年龄);
    }
}
public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例06】有参构造方法 (许杰)");
        Student stu = new Student("许杰",18);      // 实例化Student对象
        stu.read();
    }
}
图16 有参构造方法

4.2 构造方法的重载

与普通方法一样,构造方法也可以重载,在一个类中可以定义多个构造方法,但是需要每个构造方法的参数类型、参数个数或类型顺序不同。

package cn.xj.ch03.ex07;

class Student{
    private String 姓名;
    private int 年龄;
    public Student() {
        System.out.println("调用了无参数的构造方法");
    }
    public Student(String n) {
        姓名 = n;
        System.out.println("调用了一个参数的构造方法");
    }
    public Student(String n,int a) {
        姓名 = n;
        年龄 = a;
        System.out.println("调用了两个参数的构造方法");
    }
    public void read(){
        System.out.println("  我是:"+姓名+",年龄:"+年龄);
    }
}
public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例07】构造方法重载 (许杰)");
        Student stu1 = new Student("张三");
        Student stu2 = new Student("李四",18);   // 实例化Student对象
        stu1.read();
        stu2.read();
    }
}
图17 构造方法重载

4.3 默认构造方法

在Java中的每个类都至少有一个构造方法,如果在一个类中没有定义构造方法,编译系统会自动为这个类创建一个默认的构造方法,这个默认的构造方法没有参数,方法体中没有任何代码,所以Java中默认的构造方法在程序运行时什么也不做。

// 第一种写法
class Student {
}
// 第二种写法:
class Student {
   public Student(){
   }
}
// 两种写法,效果是完全一样的。

由于系统提供的默认构造方法往往不能满足需求,因此,通常需要程序员自己在类中定义构造方法。

一旦为类定义了构造方法,系统就不再提供默认的构造方法

一旦为类定义了有参构造方法,系统就不再提供默认的构造方法,此时调用 new 类名() 就会出错

package cn.xj.ch03.ex08;
class Student{
    int age;
    public Student(int n) {
        age = n;
    }
}
public class Example_xj {
    public static void main(String[] args) {
        Student stu1 = new Student(18);
        Student stu2 = new Student();  //应为 1 个实参,但实际为 0 个
    }
}
图18 定义构造方法,调用new 类名()

注意:

5. this关键字

5.1 使用this关键字调用本类中的属性

在实际开发中,如果成员变量和局部变量的名称设置成一样的,会导致成员变量和局部变量的名称冲突。

package cn.xj.ch03.ex09;
class Student {
    private String name;
    private int age;
    // 定义构造方法
    public Student(String name,int age) {
        name = name;
        age = age;
    }
    public String read(){
        return "我是:"+name+",年龄:"+age;
    }
}
public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例09】成员变量和局部变量同名冲突 (许杰)");
        Student stu = new Student("张三", 18);
        System.out.println(stu.read());
    }
}
图19 成员变量和局部变量同名冲突
package cn.xj.ch03.ex10;
class Student {
    private String name;
    private int age;
    // 定义构造方法
    public Student(String name,int age) {
        this.name = name;
        this.age = age;
    }
    public String read(){
        return "我是:"+name+",年龄:"+age;
    }
}
public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例10】this解决成员变量和局部变量同名冲突 (许杰)");
        Student stu = new Student("张三", 18);
        System.out.println(stu.read());
    }
}
图20 this解决成员变量和局部变量同名冲突

5.2 使用this关键字调用成员方法

class Student {
    public void openMouth() {
        ...
    }
    public void read() {
        this.openMouth();
        // 注意的是此处的this关键字也可以省略不写。
        // openMouth();
    }
}

5.3 使用this关键字调用构造方法

构造方法是在实例化对象时被Java虚拟机自动调用,在程序中不能像调用其他成员方法一样调用构造方法,但可以在一个构造方法中使用“this(参数1,参数2…)”的形式调用其他的构造方法。

package cn.xj.ch03.ex11;

class Student {
    private String name;
    private int age;
    public Student () {
        System.out.println("调用了无参的构造方法");
    }
    public Student (String name,int age) {
        this();                  // 调用无参的构造方法
        this.name = name;
        this.age = age;
    }
    public String read(){
        return "我是:"+name+",年龄:"+age;
    }
}
public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例11】使用this关键字调用构造方法 (许杰)");
        Student stu = new Student("张三",18);    // 实例化 Student对象
        System.out.println(stu.read());
    }
}
图21 使用this关键字调用构造方法

this调用类的构造方法时,注意三点

class Student {
    public Student () {
                 this("张三");      // 调用有参构造方法
        System.out.println("无参的构造方法被调用了。");
    }
    public Student (String name) {
        this();                      // 调用无参构造方法
        System.out.println("有参的构造方法被调用了。");
    }
}

JavaBean ---- java咖啡豆

一种特殊的Java类,一种编程规范。

代码编辑区点击鼠标右键,生成getter和setter等代码。

6. 代码块

代码块可以分为4种:普通代码块、构造块、静态代码块、同步代码块。本小节将针对普通代码块和构造块进行讲解。静态代码块将在下一小节的static关键字中进行讲解,同步代码块将在多线程部分进行讲解。

6.1 普通代码块

普通代码块就是直接在方法或是语句中定义的代码块

package cn.xj.ch03.ex12;
public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例12】普通代码块--方法中的代码块  (许杰)");
        {
            int age = 18;
            System.out.println("这是普通代码块。age:"+age);
        }
        int age = 30;
        System.out.println("age:"+age);
    }
}
图22 普通代码块

6.2 构造块

构造代码块是直接在类中定义的代码块。

package cn.xj.ch03.ex12_;

class Student{
    String name;                                //成员属性
    {
        System.out.println("我是构造代码块----直接定义在类中的代码块");    //与构造方法同级
    }
    //构造方法
    public Student(){
        System.out.println("我是Student类的构造方法");
    }
    {
        System.out.println("我是构造代码块2----直接定义在类中的代码块");    //与构造方法同级
    }
}
public class Example_xj  {
    public static void main(String[] args) {
        System.out.println("【例12_】构造代码块--直接在类中定义的代码块  (许杰)");
        Student stu1 = new Student();
        Student stu2 = new Student();
    }
}
图23 构造代码块

两点结论

7. static关键字

7.1 静态属性

package cn.xj.ch03.ex13;

class Student {
    String 姓名;                                        // 定义name属性
    int 年龄;                                 // 定义age属性
    String 所在大学 = "华北工学院";            // 假设我们本系统中 所有的学生都是同一所大学:华北工学院
    public Student(String 姓名,int 年龄){
        this.姓名 = 姓名;
        this.年龄 = 年龄;
    }
    public void info(){
        System.out.println("姓名:" + this.姓名+",年龄:" +this.年龄+
                ",所在大学:" + 所在大学);
    }
}

public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例13】所在大学 属性具有所有同学的共同属性  (许杰)");
        Student stu1 = new Student("张三",18);    // 创建学生对象
        Student stu2 = new Student("李四",19);
        Student stu3 = new Student("王五",20);
        stu1.info();
        stu2.info();
        stu3.info();
        //修改stu1对象的school的值
        stu1.所在大学 = "中北大学";
        System.out.println("修改stu1学生对象的学生信息为中北大学后");
        stu1.info();
        stu2.info();
        stu3.info();
    }
}
图24 某属性是所有成员的共同属性

静态属性访问格式

如果在Java程序中使用static修饰属性,则该属性称为静态属性(也称全局属性----所有成员共同的属性)

类名.静态属性名
或
实例对象名.静态属性名
package cn.xj.ch03.ex14;

class Student {
    String 姓名;                                        // 定义name属性
    int 年龄;                                 // 定义age属性
    static String 所在大学 = "华北工学院";            // 假设我们本系统中 所有的学生都是同一所大学:华北工学院
    public Student(String 姓名,int 年龄){
        this.姓名 = 姓名;
        this.年龄 = 年龄;
    }
    public void info(){
        System.out.println("姓名:" + this.姓名+",年龄:" +this.年龄+
                ",所在大学:" + 所在大学);
    }
}

public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例14】static 所有成员的共同属性  (许杰)");
        Student stu1 = new Student("张三",18);    // 创建学生对象
        Student stu2 = new Student("李四",19);
        Student stu3 = new Student("王五",20);
        stu1.info();
        stu2.info();
        stu3.info();
        //修改stu1对象的school的值
        stu1.所在大学 = "中北大学";
        System.out.println("修改stu1学生对象的学生信息为中北大学后");
        stu1.info();
        stu2.info();
        stu3.info();
        System.out.println("所有学生共同具备的属性 所在大学="+ Student.所在大学);
    }
}
图25 static 所有成员的共同属性

static关键字只能修饰成员变量,不能修饰局部变量,否则编译器会报错。

7.2 静态方法

在实际开发时,开发人员有时希望编写所有成员共同一致的方法(静态方法),这时就需要使用静态方法,要实现静态方法只需要在成员方法前加上static关键字。静态方法也可以通过类名和对象访问

类名.静态方法名(...)
或
实例对象名.静态方法名(...)
package cn.xj.ch03.ex15;

class Student {
    String 姓名;                                        // 定义name属性
    int 年龄;                                 // 定义age属性
    private static String 所在大学 = "华北工学院";            // 假设我们本系统中 所有的学生都是同一所大学:华北工学院
    public Student(String 姓名,int 年龄){
        this.姓名 = 姓名;
        this.年龄 = 年龄;
    }
    public void info(){
        System.out.println("姓名:" + this.姓名+",年龄:" +this.年龄+
                ",所在大学:" + 所在大学);
    }
    public static String get所在大学() {
        return 所在大学;
    }
    public static void set所在大学(String s) {
        所在大学 = s;
    }
}

public class Example_xj {
    public static void main(String[] args) {
        System.out.println("【例15】static 所有成员的共同方法  (许杰)");
        Student stu1 = new Student("张三",18);    // 创建学生对象
        Student stu2 = new Student("李四",19);
        Student stu3 = new Student("王五",20);
        stu1.info();
        stu2.info();
        stu3.info();
        //修改stu1对象的school的值
        Student.set所在大学("中北大学");
        //stu1.set所在大学("中北大学");
        System.out.println("修改Student 所在大学:为中北大学后");
        stu1.info();
        stu2.info();
        stu3.info();
        System.out.println("所有学生共同具备的属性 所在大学="+ Student.get所在大学());
    }
}
图26 static 所有成员的共同方法--静态方法

注意:静态方法只能访问静态成员,因为非静态成员需要先创建对象才能访问,即随着对象的创建,非静态成员才会分配内存。而静态方法在被调用时可以不创建任何对象。

7.3 静态代码块

在Java类中,用static关键字修饰的代码块称为静态代码块。当类被加载时,静态代码块就会执行,由于类只加载一次,所以静态代码块只执行一次。在程序中,通常使用静态代码块对类的成员变量进行初始化。

package cn.xj.ch03.ex16;

class Student{
    String name;                            //成员属性
    {
        System.out.println("我是构造代码块");
    }
    static {
        System.out.println("我是静态代码块");
    }
    public Student(){                          //构造方法
        System.out.println("我是Student类的构造方法");
    }
    {
        System.out.println("我是构造代码块2");
    }
    static {
        System.out.println("我是静态代码块2");
    }
}
class Example_xj{
    public static void main(String[] args) {
        System.out.println("【例16】static代码块 -- 只执行一次 (许杰)");
        Student stu1 = new Student();
        System.out.println("-----");
        Student stu2 = new Student();
        System.out.println();
        Student stu3 = new Student();
    }
}
图27 static 静态代码块
图28 本章源代码包名、文件名截图

返回