一、面向对象思想

1.1 面向对象思想引入

  前面我们讲过数组,当有多个数组都需要遍历时,我们可以将遍历的代码封装到方法中,需要遍历时,就调用相应的方法即可,提高代码的复用性。在对数组遍历的基础上继续增加需求,比如获取最值,数值逆序等,同样需要将这些功能封装到相应的方法中。这样继续封装会发现方法越来越多,于是就想能不能将这些方法继续进行封装呢?通过前面的讲解我们知道类是可以存放方法的,所以,我们就考虑使用类封装来这多个方法,将来再做数组的操作时,不用去找具体的方法,先找到这个类,然后使用这个类中的方法。这就是面向对象思想的编程方式。

1.2 面向过程思想概述

  我们来回想一下,之前我们完成一个需求的步骤:首先是搞清楚我们要做什么,然后在分析怎么做,最后我们再代码体现。一步一步去实现,而具体的每一步都需要我们去实现和操作。这些步骤相互调用和协作,完成我们的需求。
  在上面的每一个具体步骤中我们都是参与者,并且需要面对具体的每一个步骤和过程,这就是面向过程最直接的体现。
  那么什么是面向过程开发呢? 面向过程开发,其实就是面向着具体的每一个步骤和过程,把每一个步骤和过程完成,然后由这些功能方法相互调用,完成需求。
  面向过程的代表语言:C语言

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

1.3 面向对象思想概述

  当需求单一,或者简单时,我们一步一步去操作没问题,并且效率也挺高。可随着需求的更改,功能的增多,发现需要面对每一个步骤很麻烦了,这时就开始思索,能不能把这些步骤和功能在进行封装,封装时根据不同的功能,进行不同的封装,功能类似的封装在一起。这样结构就清晰了很多。用的时候,找到对应的类就可以了。这就是面向对象的思想。接下来我们看看面向对象到底是什么?

  面向对象是基于面向过程的编程思想。

面向过程:强调的是每一个功能的步骤
面向对象:强调的是对象,然后由对象去调用功能

1.4 面向对象的思想特点

  A:是一种更符合我们思想习惯的思想
  B:可以将复杂的事情简单化
  C:将我们从执行者变成了指挥者

【举例】
  买电脑:
    面向过程:我的了解电脑--了解我自己的需求--找对应的参数信息--去中关村买电脑--讨价还价--买回电脑
    面向对象:我知道我要买电脑 -- 班长去给我买 -- 班长就买回来了
  洗衣服:
    面向过程:把衣服脱下--找一个盆--放点洗衣粉--加点水--把衣服扔进去--搓一搓--清洗衣服--拧干--晾起来
    面向对象:把衣服脱下--打开全自动洗衣机--扔进去--一键即可--晾起来
  吃饭:
    面向过程:去超市买菜--摘菜--洗菜--切菜--炒菜--盛起来--吃
    面向对象:上饭店吃饭,你--服务员(点菜)--厨师(做菜)--服务员(端菜)--吃

1.5 面向过程和面向对象代码比较

  需求:把大象装进冰箱

【面向过程】

  动作有哪些呢?

    A:打开冰箱门
    B:装进大象
    C:关闭冰箱门

  代码体现;

class Demo {
    public static void main(String[] args) {
        /*
        System.out.println("打开冰箱门");
        //打开冰箱门的东西,我现在仅仅是为了演示,就写了一个输出语句
        //其实,它可能需要做很多操作。
        //这个时候代码就比较多一些了
        //假设我要多次打开冰箱门,
        //代码一多,每次都写一遍,麻烦不
        //我们就应该用方法改进
        
        System.out.println("装进大象");
        System.out.println("关闭冰箱门");
        */
        
        //写了方法以后,调用就改变了
        open();
        in();
        close();
    }
    
    public static void open() {
        System.out.println("打开冰箱门");
    }
    
    public static void in() {
        System.out.println("装进大象");
    }
    
    public static void close() {
        System.out.println("关闭冰箱门");
    }
}

【面向对象】

  我们怎么才能更符合面向对象思想呢?

    A:有哪些类呢?
    B:每个类有哪些东西呢?
    C:类与类直接的关系是什么呢?

  把大象装进冰箱的分析?

    A:有哪些类呢?

      大象
      冰箱
      Demo

    B:每个类有哪些东西呢?

      大象:
        进去
      冰箱:
        开门
        关门
      Demo:
      main方法
    C:类与类直接的关系是什么呢?
      Demo中使用大象和冰箱类的功能。

class 大象 {
    public static void in() {
        System.out.println("装进大象");
    }
}

class 冰箱 {
    public static void open() {
        System.out.println("打开冰箱门");
    }
    
    public static void close() {
        System.out.println("关闭冰箱门");
    }
}

class Demo {
    public static void main(String[] args) {
        冰箱调用开门
        大象调用进去
        冰箱调用关门
    }
}

1.6 面向对象开发、设计、特征

【面向对象开发】

  就是不断的创建对象,使用对象,指挥对象做事情。

【面向对象设计】

  其实就是在管理和维护对象之间的关系。

【面向对象特征】

  封装(encapsulation)
  继承(inheritance)
  多态(polymorphism)

二、类与对象的关系

  我们学习编程语言,就是为了模拟现实世界的事物,实现信息化。比如:去超市买东西的计费系统,去银行办业务的系统。
  我们如何表示一个现实世界事物呢:
    属性:该事物的描述信息
    行为:该事物能够做什么
  举例:学生事物

    姓名,年龄,性别...

    学习,吃饭,睡觉

  我们学习的Java语言最基本单位是类,所以,我们就应该把事物用一个类来体现。

  事物:       类:
    属性       成员变量
    行为          成员方法

  类:是一组相关的属性和行为的集合。是一个抽象的概念。

  对象:是该类事物的具体表现形式。具体存在的个体

  举例:
    学生:类
    班长:对象

  JavaSE学习笔记(六)—— 面向对象 随笔 第1张

【类的定义】

  现实世界的事物:

属性    人的身高,体重等
行为    人可以学习,吃饭等

  Java中用class描述事物也是如此:

成员变量    就是事物的属性
成员方法    就是事物的行为

  定义类其实就是定义类的成员(成员变量和成员方法)

【如何创建对象呢】

  格式:类名 对象名 = new 类名();

【案例】

  定义一个学生类和学生测试类

/*    
    学生事物:
        属性:姓名,年龄,地址...
        行为:学习,吃饭,睡觉...
        
    把事物要转换为对应的类:
    
    学生类:
        成员变量:姓名,年龄,地址...
        成员方法:学习,吃饭,睡觉...
    
    首先我们应该定义一个类,然后完成类的成员。
   如何使用成员变量呢?对象名.变量名
  如何使用成员方法呢?对象名.方法名(...)
*/ //这是我的学生类 class Student { //定义变量 //姓名 String name; //年龄 int age; //地址 String address; //定义方法 //学习的方法 public void study() { System.out.println("学生爱学习"); } //吃饭的方法 public void eat() { System.out.println("学习饿了,要吃饭"); } //睡觉的方法 public void sleep() { System.out.println("学习累了,要睡觉"); } } //这是学生测试类 class StudentDemo { public static void main(String[] args) { //类名 对象名 = new 类名(); Student s = new Student(); //输出成员变量值 //System.out.println(s.name); //System.out.println(s.age); //System.out.println(s.address); //改进写法 System.out.println(s.name+"---"+s.age+"---"+s.address); //给成员变量赋值 s.name = "林青霞"; s.age = 27; s.address = "北京"; //赋值后的输出 System.out.println(s.name+"---"+s.age+"---"+s.address); //调用方法 s.study(); s.eat(); s.sleep(); } }

  定义一个手机类

/*
    手机事物:
        属性:品牌,价格,颜色...
        行为:打电话,发短信,玩游戏...
        
    手机类:
        成员变量:品牌,价格,颜色
        成员方法:打电话,发短信,玩游戏
*/
class Phone {
    //品牌
    String brand;
    //价格
    int price;
    //颜色
    String color;
    
    //打电话的方法
    public void call(String name) {
        System.out.println("给"+name+"打电话");
    }
    
    //发短信的方法
    public void sendMessage() {
        System.out.println("群发短信");
    }
    
    //玩游戏的方法
    public void playGame() {
        System.out.println("玩游戏");
    }
}

三、对象内存图

【一个对象的内存图】

JavaSE学习笔记(六)—— 面向对象 随笔 第2张

【二个对象的内存图】

JavaSE学习笔记(六)—— 面向对象 随笔 第3张

【三个对象的内存图】

JavaSE学习笔记(六)—— 面向对象 随笔 第4张

四、成员变量和局部变量的区别

  1. 在类中的位置不同
    成员变量:在类中方法外
    局部变量:在方法定义中或者方法声明上
  2. 在内存中的位置不同
    成员变量:在堆内存
    局部变量:在栈内存
  3. 生命周期不同
    成员变量:随着对象的创建而存在,随着对象的消失而消失
    局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
  4. 初始化值不同
    成员变量:有默认初始化值
    局部变量:没有默认初始化值,必须定义,赋值,然后才能使用。

【注意事项】

   局部变量名称可以和成员变量名称一样,在方法中使用的时候,采用的是就近原则

class Varialbe {
    //成员变量
    //int num = 10;
    int num; //0
    
    public void show() {
        //int num2 = 20; //局部变量
        //可能尚未初始化变量num2
        //int num2; //没有默认值
        int num2 = 20;
        System.out.println(num2);
        
        //int num = 100;
        System.out.println(num);
    }
}

class VariableDemo {
    public static void main(String[] args) {
        Varialbe v = new Varialbe();
        
        System.out.println(v.num); //访问成员变量
        
        v.show();            
    }
}

五、形式参数问题

  • 基本类型:形式参数的改变不影响实际参数
  • 引用类型:形式参数的改变直接影响实际参数
//形式参数是基本类型
class Demo {
    public int sum(int a,int b) {
        return a + b;
    }
}

//形式参数是引用类型
class Student {
    public void show() {
        System.out.println("我爱学习");
    }
}

class StudentDemo {
    //如果你看到了一个方法的形式参数是一个类类型(引用类型),这里其实需要的是该类的对象。
    public void method(Student s) { //调用的时候,把main方法中的s的地址传递到了这里 Student s = new Student();
        s.show();
    }
}

class ArgsTest {
    public static void main(String[] args) {
        //形式参数是基本类型的调用
        Demo d = new Demo();
        int result = d.sum(10,20);
        System.out.println("result:"+result);
        System.out.println("--------------");
        
        //形式参数是引用类型的调用
        //需求:我要调用StudentDemo类中的method()方法
        StudentDemo sd = new StudentDemo();
        //创建学生对象
        Student s = new Student();
        sd.method(s); //把s的地址给到了这里
    }
}

六、匿名对象

  匿名对象:就是没有名字的对象。

【应用场景】

  1. 调用方法,仅仅只调用一次的时候。
    注意:调用多次的时候,不适合。因为每一次调用都会创建新的对象,浪费内存空间
  2. 匿名对象可以作为实际参数传递

【好处】

  匿名对象调用完毕就是垃圾。可以被垃圾回收器回收。

class Student {
    public void show() {
        System.out.println("我爱学习");
    }
}

class StudentDemo {
    public void method(Student s) {
        s.show();
    }
}

class NoNameDemo {
    public static void main(String[] args) {
        //带名字的调用
        Student s = new Student();
        s.show();
        s.show();//这里用的都是同一个对象
        System.out.println("--------------");
        
        //匿名对象
        //new Student();
        //匿名对象调用方法
        new Student().show();
        new Student().show(); //这里其实是重新创建了一个新的对象
        System.out.println("--------------");
        
        
        //匿名对象作为实际参数传递
        StudentDemo sd = new StudentDemo();
        //Student ss = new Student();
        //sd.method(ss); //这里的s是一个实际参数
        //匿名对象
        sd.method(new Student());
        
        //在来一个
        new StudentDemo().method(new Student());
     }
}

七、封装

  定义一个学生类:
    成员变量:name,age
    成员方法:show()方法

class Student {
    //姓名
    String name;
    //年龄
    private int age;
    
    //写一个方法对数据进行校验
    /*
        返回值类型:void
        参数列表:int a
    */
    public void setAge(int a) {
        if(a < 0 || age > 120) {
            System.out.println("你给的年龄有问题");
        }else {
            age = a;
        }
    }
    
    //show()方法,显示所有成员变量值
    public void show() {
        System.out.println("姓名:"+name);
        System.out.println("年龄:"+age);
    }
}

class StudentDemo {
    public static void main(String[] args) {
        //创建学生对象
        Student s = new Student();
        s.show();
        System.out.println("--------------");
        
        //给成员变量赋值
        s.name = "林青霞";
        //s.age = 27;
        s.setAge(27);
        s.show();
        System.out.println("--------------");
        
        //给age赋值
        //s.age = -27; //这个数据是不合理的
        //通过方法给值
        s.setAge(-27);
        s.show();
        System.out.println("--------------");
    }
}

  我们在使用这个案例的过程中,发现了一个问题:通过对象去给成员变量赋值,可以赋值一些非法的数据。这是不合理的。
  应该是这个样子的:在赋值之前,先对数据进行判断。判断到底在哪里做比较合适呢?StudentDemo类是一个测试类,测试类一般只创建对象,调用方法。 所以,这个判断应该定义在Student类中。
  而我们在成员变量的位置可不可以进行数据判断呢?是不可以的,因为做数据校验,必须要依靠一些逻辑语句。逻辑语句是应该定义在方法中的,所以,我们最终决定在Student类中提供一个方法来对数据进行校验。

  按照我们前面的分析,我们给出了一个方法进行校验。但是呢,它偏偏不调用方法来赋值,还是直接赋值了,这样我们的方法就没有起到作用。我就应该要求你必须使用我的方法,而不能直接调用成员变量赋值。怎么去强制要求不能直接使用成员变量呢?针对这种情况,Java就提供了一个关键字 private。

  其实我讲到现在讲解的是一个封装的思想。

7.1 封装概述

  封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。   

【好处】

  • 隐藏实现细节,提供公共的访问方式
  • 提高了代码的复用性
  • 提高安全性。

【封装原则】

  • 将不需要对外提供的内容都隐藏起来。
  • 把属性隐藏,提供公共方法对其访问。

7.2 private关键字

  • private一个权限修饰符
  • private可以修饰成员变量和成员方法
  • 被private修饰的成员只能在本类中被访问
class Demo {
    //int num = 10;
    //用private修饰
    private int num = 10;
    
    public void show() {
        System.out.println(num);
    }
    
    private void method() {
        System.out.println("method");
    }
    
    public void function() {
        method();
    }
}

class PrivateDemo {
    public static void main(String[] args) {
        Demo d = new Demo();
        //不能方法私有的成员变量
        //System.out.println(d.num);
        d.show();
        //不能访问私有的成员方法
        //d.method();
        d.function();
    }
}

【封装和private的应用】

  • 把成员变量用private修饰
  • 提供对应的getXxx()和setXxx()方法
//定义学生类
class Student {
    //姓名
    private String name;
    //年龄
    private int age;
    
    //姓名获取值
    public String getName() {
        return name;
    }
    
    //姓名设置值
    public void setName(String n) {
        name = n;
    }
    
    //年龄获取值
    public int getAge() {
        return age;
    }
    
    //年龄赋值
    public void setAge(int a) {
        age = a;
    }
}

//测试类
class StudentTest {
    public static void main(String[] args) {
        //创建学生对象
        Student s = new Student();
        
        //使用成员变量
        //错误:被私有修饰了,外界不能直接访问了
        //System.out.println(s.name+"---"+s.age);
        System.out.println(s.getName()+"---"+s.getAge());
        
        //给成员变量赋值
        //s.name = "林青霞";
        //s.age = 27;
        //通过方法给赋值
        s.setName("林青霞");
        s.setAge(27);
        System.out.println(s.getName()+"---"+s.getAge());
    }
}

八、this关键字

  拿上面的Student类作为例子:

//定义学生类
class Student {
    //姓名
    private String name;
    //年龄
    private int age;
    
    //姓名获取值
    public String getName() {
        return name;
    }
    
    //姓名设置值
    public void setName(String n) {
        name = n;
    }
    
    //年龄获取值
    public int getAge() {
        return age;
    }
    
    //年龄赋值
    public void setAge(int a) {
        age = a;
    }
}

  我们曾经说:起名字要做到见名知意。上面的setName(String n)和setAge(int a)显然不符合我们的命名规范,为了做到见明知意,应该定义为setName(String name)和setAge(int age),改进上面代码:

//定义学生类
class Student {
    //姓名
    private String name;
    //年龄
    private int age;
    
    //姓名获取值
    public String getName() {
        return name;
    }
    
    //姓名设置值
    public void setName(String name) { //name = "林青霞";
        name = name;
    }
    
    //年龄获取值
    public int getAge() {
        return age;
    }
    
    //年龄赋值
    public void setAge(int age) {
        age = age;
    }
}

//测试类
class StudentTest {
    public static void main(String[] args) {
        //创建学生对象
        Student s = new Student();
        
        //给成员变量赋值
        s.setName("林青霞");
        s.setAge(27);
        //获取数据
        System.out.println(s.getName()+"---"+s.getAge());
    }
}

  当我们在测试类中给Student赋值时,却发现获取不到我们所期望的值。这时因为变量的使用规则:就近原则。调用s.setName("林青霞")赋值的时候,setName()方法中的name变量其实是该方法内部的局部变量,给它赋值并不会影响Student类中成员变量name的结果,此时getName()得到的结果仍然是默认初始化值null。

  那我们是否可以这样写:

   //姓名设置值
    public void setName(String name) { //name = "林青霞";
        //name = name; //变量的使用规则:就近原则
        Student.name = name;//错误的
    }

  这里是类名,目前还没有说过类似的用法,所以这个是有问题的。这里的调用只能通过对象名,这个对象如果存在,它应该代表的是Student的一个对象。那么,谁能够代表当前类的对象呢? java就提供了一个关键字 this。

  this:是当前类的对象引用。简单的记,它就代表当前类的一个对象。哪个对象调用那个方法,this就代表那个对象

  将上述代码改进:

class Student {
    private String name;
    private int age;
    
    public String getName() {
        return name; //这里其实是隐含了this
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public int getAge() {
        return age;
    }
    
    public void setAge(int age) {
        this.age = age;
    }
}

class StudentTest2 {
    public static void main(String[] args) {
        //创建一个对象
        Student s1 = new Student();
        s1.setName("林青霞");
        s1.setAge(27);
        System.out.println(s1.getName()+"---"+s1.getAge());
        
        //创建第二个对象
        Student s2 = new Student();
        s2.setName("刘意");
        s2.setAge(30);
        System.out.println(s2.getName()+"---"+s2.getAge());
    }
}

对应的内存图为:

JavaSE学习笔记(六)—— 面向对象 随笔 第5张

【this的应用场景】

  解决局部变量隐藏成员变量

九、构造方法

  构造方法:给对象的数据进行初始化。

【格式】

  • 方法名与类名相同
  • 没有返回值类型,连void都没有
  • 没有具体的返回值
class Student {
    private String name; //null
    private int age; //0
    
    public Student() {
        System.out.println("这是构造方法");
    }
}

class ConstructDemo {
    public static void main(String[] args) {
        //创建对象
        Student s = new Student();
        System.out.println(s); //Student@e5bbd6
    }
}

JavaSE学习笔记(六)—— 面向对象 随笔 第6张

  我们一直在使用构造方法,但是,我们却没有定义构造方法,用的是哪里来的呢?

【构造方法的注意事项】

  • 如果我们没有给出构造方法,系统将自动提供一个无参构造方法。(可以通过反编译工具看出)
  • 如果我们给出了构造方法,系统将不再提供默认的无参构造方法。注意:这个时候,如果我们还想使用无参构造方法,就必须自己给出。建议永远自己给出无参构造方法
  • 构造方法也是可以重载的
class Student {
    private String name;
    private int age;

    public Student() {
        System.out.println("这是无参构造方法");
    }
    
    //构造方法的重载格式
    public Student(String name) {
        System.out.println("这是带一个String类型的构造方法");
        this.name = name;
    }
    
    public Student(int age) {
        System.out.println("这是带一个int类型的构造方法");
        this.age = age;
    }
    
    public Student(String name,int age) {
        System.out.println("这是一个带多个参数的构造方法");
        this.name = name;
        this.age = age;
    }
    
    public void show() {
        System.out.println(name+"---"+age);
    }
}

class ConstructDemo2 {
    public static void main(String[] args) {
        //创建对象
        Student s = new Student();
        s.show();
        System.out.println("-------------");
        
        //创建对象2
        Student s2 = new Student("林青霞");
        s2.show();
        System.out.println("-------------");
        
        //创建对象3
        Student s3 = new Student(27);
        s3.show();
        System.out.println("-------------");
        
        //创建对象4
        Student s4 = new Student("林青霞",27);
        s4.show();
    }
}

【注意】  

  A:给成员变量赋值有两种方式:setXxx()和构造方法,可以只写一种;

  B:如果不单独获取数据,可以不写getXxx()方法。

  学完构造方法后,以后再提类的组成:

  • 成员变量
  • 构造方法
  • 成员方法
    根据返回值:
        void类型
        非void类型
    形式参数:
        空参方法
        非空参方法

十、类的初始化过程

  Student s = new Student();在内存中做了哪些事情?

  1. 加载Student.class文件进内存
  2. 在栈内存为s开辟空间
  3. 在堆内存为学生对象开辟空间
  4. 对学生对象的成员变量进行默认初始化
  5. 对学生对象的成员变量进行显示初始化
  6. 通过构造方法对学生对象的成员变量赋值
  7. 学生对象初始化完毕,把对象地址赋值给s变量

 JavaSE学习笔记(六)—— 面向对象 随笔 第7张

十一、面向对象练习

  定义一个长方形类,定义 求周长和面积的方法,

/*
    长方形的类:
        成员变量:
            长,宽
        成员方法:
            求周长:(长+宽)*2;
            求面积:长*宽

*/

class ChangFangXing {
    //长方形的长
    private int length;
    //长方形的宽
    private int width;
    
    public ChangFangXing(){}
    
    //仅仅提供setXxx()即可
    public void setLength(int length) {
        this.length = length;
    }
    
    public void setWidth(int width) {
        this.width = width;
    }
    
    //求周长
    public int getZhouChang() {
        return (length + width) * 2;
    }
    
    //求面积
    public int getArea() {
        return length * width;
    }
}

class Test2 {
    public static void main(String[] args) {
        //创建键盘录入对象
        Scanner sc = new Scanner(System.in);
        
        System.out.println("请输入长方形的长:");
        int length = sc.nextInt();
        System.out.println("请输入长方形的宽:");
        int width = sc.nextInt();
        
        //创建对象
        ChangFangXing cfx = new ChangFangXing();
        //先给成员变量赋值
        cfx.setLength(length);
        cfx.setWidth(width);
        
        System.out.println("周长是:"+cfx.getZhouChang());
        System.out.println("面积是:"+cfx.getArea());
    }
}

  定义一个员工类,自己分析出几个成员,然后给出成员变量,构造方法,getXxx()/setXxx()方法,以及一个显示所有成员信息的方法。并测试。

/*
    分析:
        员工
            成员变量:
                员工编号,姓名,年龄
            构造方法:
                无参构造方法
            成员方法:
                getXxx()/setXxx()
                show();
*/
class Employee {
    //员工编号
    private String employeeId;
    //姓名
    private String name;
    //年龄
    private int age;
    
    //构造方法
    public Employee() {}
    
    //getXxx()/setXxx()
    public String getEmployeeId() {
        return employeeId;
    }
    
    public void setEmployeeId(String employeeId) {
        this.employeeId = employeeId;
    }
    
    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 void show() {
        System.out.println("员工编号是:"+employeeId+"的这个人是:"+name+"的年龄是:"+age);
    }
}

class EmployeeTest {
    public static void main(String[] args) {
        //创建对象
        Employee e = new Employee();
        
        //给成员变量赋值
        e.setEmployeeId("czbk9527");
        e.setName("唐伯虎");
        e.setAge(18);
        
        //获取数据
        //System.out.println(e.getEmployeeId()+"---"+e.getName()+"---"+e.getAge());
    
        //我们在Employee类中定义了一个show方法。所以,我们改进一下,使用show方法
        e.show();
    }
}

十二、static关键字

  定义一个人类

class Person {
    //姓名
    String name;
    //年龄
    int age;
    //国籍
    //String country;
    static String country;
    
    public Person(){}
    
    public Person(String name,int age) {
        this.name = name;
        this.age = age;
    }
    
    public Person(String name,int age,String country) {
        this.name = name;
        this.age = age;
        this.country = country;
    }
    
    public void show() {
        System.out.println("姓名:"+name+",年龄:"+age+",国籍:"+country);
    }
}

class PersonDemo {
    public static void main(String[] args) {
        //创建对象1
        Person p1 = new Person("邓丽君",16,"中国");
        p1.show();
        
        //创建对象2
        //Person p2 = new Person("杨幂",22,"中国");
        //p2.show();
        Person p2 = new Person("杨幂",22);
        p2.show();
        
        //创建对象3
        //Person p3 = new Person("凤姐",20,"中国");
        //p3.show();
        Person p3 = new Person("凤姐",20);
        p3.show();
        
        p3.country = "美国";
        p3.show();
        
        p1.show();
        p2.show();
    }
}

  姓名和年龄都是变化的,这个我能接收,因为每个人的姓名和年龄是不同的。但是,我们现在选取的几个人都是中国人,他们的国籍是一样的。一样的国籍,我每次创建对象,在堆内存都要开辟这样的空间,我就觉得有点浪费了。怎么办呢?

  针对多个对象有共同的这样的成员变量值的时候,Java就提高了一个关键字来修饰:static。

【static的内存图解】——静态的内容存在于方法区的静态区

JavaSE学习笔记(六)—— 面向对象 随笔 第8张

【static的特点】——(它可以修饰成员变量,还可以修饰成员方法)

  1. 随着类的加载而加载
    回想main方法,main方法是static修饰的,所以它随着类的加载而加载。想象一下,如果main方法在class文件加载后它还没有加载,那么jvm调用的时候就找不到它了
  2. 优先于对象存在
  3. 被类的所有对象共享
    举例:咱们班级的学生应该共用同一个班级编号。
    其实这个特点也是在告诉我们什么时候使用静态?
        如果某个成员变量是被所有对象共享的,那么它就应该定义为静态的。
    举例:
        饮水机(用静态修饰)
        水杯(不能用静态修饰)
  4. 可以通过类名调用
    其实它本身也可以通过对象名调用。
    推荐使用类名调用。

  静态修饰的内容一般我们称其为:与类相关的,类成员

【static关键字注意事项】

  1. 在静态方法中是没有this关键字的
    如何理解呢?
        静态是随着类的加载而加载,this是随着对象的创建而存在。
        静态比对象先存在。
  2. 静态方法只能访问静态的成员变量和静态的成员方法;非静态方法访问的成员变量,可以是静态的,也可以是非静态的,非静态方法访问的成员方法,可是是静态的成员方法,也可以是非静态的成员方法。简单记:静态只能访问静态
class Teacher {
    public int num = 10;
    public static int num2 = 20;
    
    public void show() {
        System.out.println(num); //隐含的告诉你访问的是成员变量
        System.out.println(this.num); //明确的告诉你访问的是成员变量
        System.out.println(num2);
        
        //function();
        //function2();
    }
    
    public static void method() {
        //无法从静态上下文中引用非静态 变量 num
        //System.out.println(num);
        System.out.println(num2);
        
        //无法从静态上下文中引用非静态 方法 function()
        //function();
        function2();
    }
    
    public void function() {
    
    }
    
    public static void function2() {
    
    }
}

class TeacherDemo {
    public static void main(String[] args) {
        //创建对象
        Teacher t = new Teacher();
        t.show();
        System.out.println("------------");
        t.method();
    }
}

【静态变量和成员变量的区别】

  • 所属不同
    静态变量属于类,所以也称为为类变量
    成员变量属于对象,所以也称为实例变量(对象变量)
  • 内存中位置不同
    静态变量存储于方法区的静态区
    成员变量存储于堆内存
  • 内存出现时间不同
    静态变量随着类的加载而加载,随着类的消失而消失
    成员变量随着对象的创建而存在,随着对象的消失而消失
  • 调用不同
    静态变量可以通过类名调用,也可以通过对象调用
    成员变量只能通过对象名调用

【main方法讲解】

  public static void main(String[] args) {...}

  public:公共的,访问权限是最大的。由于main方法是被jvm调用,所以权限要够大。

  static:静态的,不需要创建对象,通过类名就可以。方便jvm的调用。
  void:因为我们曾经说过,方法的返回值是返回给调用者,而main方法是被jvm调用。你返回内容给jvm没有意义。
  main:是一个常见的方法入口。我见过的语言都是以main作为入口。
  String[] args:这是一个字符串数组。值去哪里了?
    这个东西到底有什么用啊?怎么给值啊?这个东西早期是为了接收键盘录入的数据的。格式是:java MainDemo hello world java

十三、代码块

  在Java中,使用{}括起来的代码被称为代码块。根据其位置和声明的不同,可以分为

  • 局部代码块:局部位置,用于限定变量的生命周期。
  • 构造代码块:在类中的成员位置,用{}括起来的代码。每次调用构造方法执行前,都会先执行构造代码块。
    作用:可以把多个构造方法中的共同代码放到一起,对对象进行初始化。

  • 静态代码块:在类中的成员位置,用{}括起来的代码,只不过它用static修饰了。
    作用:一般是对类进行初始化。

  静态代码块,构造代码块,构造方法的执行顺序?静态代码块 -- 构造代码块 -- 构造方法

  注意:静态代码块只执行一次;构造代码块每次调用构造方法都执行

class Code {
    //静态代码块
    static {
        int a = 1000;
        System.out.println(a);
    }

    //构造代码块
    {
        int x = 100;
        System.out.println(x);
    }
    
    //构造方法
    public Code(){
        System.out.println("code");
    }
    
    //构造方法
    public Code(int a){
        System.out.println("code");
    }
    
    //构造代码块
    {
        int y = 200;
        System.out.println(y);
    }
    
    //静态代码块
    static {
        int b = 2000;
        System.out.println(b);
    }
}

class CodeDemo {
    public static void main(String[] args) {
        //局部代码块
        {
            int x = 10;
            System.out.println(x);
        }
        //找不到符号
        //System.out.println(x);
        {
            int y = 20;
            System.out.println(y);
        }
        System.out.println("---------------");
        
        Code c = new Code();//1000  2000  100  200  code    
        System.out.println("---------------");
        Code c2 = new Code();//100  200  code
        System.out.println("---------------");
        Code c3 = new Code(1);//100  200  code
    }
}

  写程序的执行结果。

class Student {
    static {
        System.out.println("Student 静态代码块");
    }
    
    {
        System.out.println("Student 构造代码块");
    }
    
    public Student() {
        System.out.println("Student 构造方法");
    }
}

class StudentDemo {
    static {
        System.out.println("林青霞都60了,我很伤心");
    }
    
    public static void main(String[] args) {
        System.out.println("我是main方法");
        
        Student s1 = new Student();
        Student s2 = new Student();
    }
}

  JavaSE学习笔记(六)—— 面向对象 随笔 第9张

 

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄