zoukankan      html  css  js  c++  java
  • Java——面向对象——基础

    概述

    对象,就是指客观存在的事物,万物皆对象。

    • 客观存在的任何一种事物,都可以看作为程序中的对象
    • 使用面向对象思想可以将复杂的问题简单化
    • 将我们从执行者的位置,变成了指挥者

    面向对象和面向过程的思想对比

    面向过程编程

    是一种以过程为中心的编程思想,实现功能的每一步,都是自己实现的。

    面向对象编程

    是一种以对象为中心的编程思想,通过指挥对象实现具体的功能。

    什么是类

    类是对现实生活中一类具有共同属性和行为的事物的抽象。简单的理解的就是类是对事物,也就是对象的一种描述,可以将类理解为一张设计图,可以根据设计图,创造出具体存在的事物。

    可以根据类创造对象。

    类的组成

    • 属性:该事物的各种特征,例如学生事物的属性,姓名、年龄毕业院校...
    • 行为:该事物存在的功能,就是能够做的事情,例如学生的行为,学习、Java开发编程。

    类和对象的关系

    • 类:是对现实生活中一类具有共同属性和行为的事物的抽象,类就是对象的描述
    • 对象:是能够看得到摸得着的真实存在的实体,对象就是类的实体

    类的定义

    说明

    类的组成是属性和行为,属性在代码中可以通过成员变量(类中方法外的变量)来体现。行为在代码中可以通过成员方法来体现,和普通方法类似,去掉关键字static即可。

    步骤

    定义类 ——》 定义类的成员变量 ——》编写类的成员方法

    代码实现如下

    public class 类名 {
        // 成员变量
        变量1的数据类型 变量1;
        变量2的数据类型 变量2;
        ...
        // 成员方法
        方法1;
        方法2;
        ...
    }
    

    比如创建一个Student学生类,学生类的成员变量有姓名(name)、年龄(age),成员方法有学习(study),如下

    // 属性 姓名、年龄
    // 成员变量 跟定义普通对象的格式一样,只不过位置发生了改变,类中方法外
    String name;
    int age;
    
    // 行为 学习
    // 成员方法 跟普通定义方法的格式一样,去掉了static关键字
    public void study(){
        System.out.println("学习");
    }
    

    这样,一个基本的类就定义好了。

    对象的创建

    参照已经定义好的类,我们可以在测试类中来创建对象,格式如下

    类名 对象名 = new 类名();
    

    例子

    Student stu = new Student();
    

    对象的使用

    在测试类中使用对象的格式如下

    // 使用成员变量
    对象名.对象名
    
    // 使用成员方法
    对象名.方法名()
    

    例子

    System.out.println(stu.age);   // 0
    stu.study();   // 学习
    

    这里需要注意的是,即使我们没有给对象的属性赋值,也还是可以拿到具体的值,这里叫做默认初始化值,不会编译出错,比如String 为 null, int 为 0。

    也可以对属性进行赋值操作,如下

    stu.name = "张三";
    stu.age = 27;
    System.out.println(stu.name);   // 张三
    System.out.println(stu.age);   // 27
    

    对象的内存存储

    有如下俩个类,一个Student类,一个TestStudent测试类

    Student

    public class Student {
        String name;
        int age;
        
        public void study(){
            System.out.println("学习");
        }
    }
    

    TestStudent

    public class TestStudent {
        public static void main(String[] args) {
            Student stu = new Student();
            System.out.println(stu.age);   // 0
            stu.name = "张三";
            stu.age = 27;
            System.out.println(stu.name);   // 张三
            System.out.println(stu.age);   // 27
            stu.study();   // 学习
        }
    }    

    首先拥有主方法的测试类的字节码文件(TestStudent.class)加载进方法区,目前这个字节码文件中只有一个主方法main,主方法被虚拟机自动调用执行,进入到栈内存,第一句代码Student = stu...就是声明了一个对象类型的变量,由于内存中没有Student这个类,所以系统这一步也会把Student这个类的字节码文件(Student.class)加载进方法区,加载进来之后,成员变量和成员方法在方法区都是存在的,加载进来之后,继续 new Student(),有new就会进堆,自动在堆内存中开辟空间,产生地址,由于对象是根据类来创建的,所以类中存在的成员变量在堆内存当中也同时存在着这么一份,堆内存中的数据都有自己的默认初始化值,所以name,age都有了自己的默认初始化值,null和0,此时,成员方法是不会进入堆内存的,但是,堆内存中是会有那么一块地址是用于存在方法的引用地址的,将来可以通过这个地址找到方法区中的成员方法,此时就可以把堆内存中的地址赋值给stu了,所以如果此时打印stu,打印的就是地址值,接下来打印成员变量,就可以通过地址值找到堆内存中的这块内存,也可以根据name和age继续找到成员变量的值,null和0,并且改变它们。调用study方法是通过stu找到堆内存中的这块地址,然后再通过保存过的这个地址,找到方法区中的字节码文件的study方法,找到之后,把study方法加载进栈内存当中运行,执行完study里面的功能之后,就会从栈内存中弹栈消失。由于study()是主方法中的最后一句代码,study调用完毕之后,主方法也会从栈内存当中弹栈消失。至此,程序执行完毕。

    注意

    如果再次创建Student对象,是不会再次Student这个类的字节码文件(Student.class)加载进方法区的。

     俩个引用指向同一个对象

    情况如下,有俩个类

    Student

    public class Student {
        String name;
        int age;
    
        public void study(){
            System.out.println("学习");
        }
    }
    

    TestStudent

    public class TestStudent {
        public static void main(String[] args) {
            Student stu1 = new Student();
            stu1.name = "张三";
            Student stu2 = stu1;
            stu2.name = "李四";
            System.out.println(stu1.name + "------" + stu2.name);   // 李四------李四
        }
    }
    

    由于俩个引用指向了同一个内存空间,所以只要一个改变了对象,俩个再次取值看到的就是改动之后的结果了。

    这里我可以把对象变量赋值为null来断开连接,如下:

    stu1 = null;
    System.out.println(stu1.name);   // NullPointerException(空指针异常)
    

    如果设为null之后,再次通过stu1取属性值,就会提示空指针异常。此时不会影响另一个引用(stu2),我们还是可以通过stu2找到堆内存中的这块地址,如下

    stu1 = null;
    // System.out.println(stu1.name);   // NullPointerException(空指针异常)
    System.out.println(stu2.name);   // 李四
    

    如果之后又将stu2赋值为null,此时就没有引用能够找到堆内存中的这块地址内容了,这块内容就成了内存中的垃圾对象,垃圾对象会被Java的垃圾回收器在空闲的时候,自动进行清理。下面有描述。

    垃圾回收

    当堆内存中,对象或数组产生的地址,通过任何方式都不能被找到后,就会被判定为内存中的"垃圾","垃圾"会被Java垃圾回收器,空闲的时候,自动清理。有部分语言,"垃圾"是需要程序员手动清理的。

    成员变量和局部变量

    • 成员变量——就是类中方法外的变量,判断一个变量是不是成员变量,就看它是不是类中方法外的变量,就就可以了
    • 局部变量——就是方法当中的变量
    public class Student {
        String name;
        int age;
    
        public void study(){
            int i = 0;
            System.out.println("学习");
        }
    }
    

    上面代码,name 和 age 就是成员变量,study方法中的 i 就是局部变量。

    成员变量和局部变量有如下区别

    区别 成员变量 局部变量
    类中位置不同 类中方法外 方法内或者方法声明上(形参)
    内存中位置不同 堆内存 栈内存
    生命周期不同 随着对象的存在而存在,随着对象的消失而消失 随着方法的调用而存在,随着方法的调用完毕消失
    初始化值不同 有默认的初始值 么有默认的初始化值,必须先定义,赋值,才能使用

    封装

    private

    private是一个访问修饰符,这个单词的意思是私有的,它的作用可以用来修饰成员(变量和方法)。被它修饰过的成员,只能在本类中进行访问。如下

    public class Student {
        private String name;
        int age;
    
        public void show(){
            System.out.println(name + "-----" + age);
        }
    }
    

    上面Student类中的name成员变量就被private修饰符修饰过了。这样的话,其他的类就无法访问它了。

    public class TestStudent {
        public static void main(String[] args) {
            Student stu = new Student();
            stu.name = "张三";   // name在com.baidu.Student中是private访问控制
        }
    }
    

    使用访问修饰符修饰成员就是可以提高了数据的安全性,如果使用private,还需要提供如下的操作

    • 提供"get变量名()"方法,用于获取成员变量的值,方法用public修饰
    • 提供"set变量名(参数)"方法,用于设置成员变量的值,方法用public的值
    public 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;
        }
        public void show(){
            System.out.println(name + "-----" + age);
        }
    }
    

    如此使用的直观影响就是在其他类中是无法通过"对象.变量名"的方式获取和修改成员变量了,但是也提高了安全性,比如用户在设置年龄的时候,我们在设置年龄的方法中(setAge),加以判断,必须在某个范围内,才能设置成功。如下

    // Student.java
    public void setAge(int a){
        if(a >= 0 && a <= 120){
            age = a;
        }else{
            System.out.println("您设置的年龄有误");
        }
    
    }
    
    // TestStudent.java
    Student stu = new Student();
    stu.setAge(130);   // 您设置的年龄有误
    

    总结:今天在定义成员变量时,都需要采用private修饰。再提供get、set方法,从而提高代码的安全性。

    this

    在Java中,当成员变量和局部变量重名时,Java会采用就近原则,如下

    // Student.java
    public class Student {
        private int age = 10;
    
        public void show() {
            int age = 20;
            System.out.println(age);
        }
    }
    
    // ThisTest01.java
    public class ThisTest01 {
        public static void main(String[] args) {
            Student stu = new Student();
            stu.show();   // 20
        }
    }
    

    这时,如果需要访问打印成员变量age,而不是局部变量age,就可以加上this关键字,如下

    // Student .java
    public class Student {
        private int age = 10;
    
        public void show() {
            int age = 20;
            System.out.println(this.age);
        }
    }
    
    // ThisTest01.java
    public class ThisTest01 {
        public static void main(String[] args) {
            Student stu = new Student();
            stu.show();   // 10
        }
    }
    

    所以,this关键字的作用就是可以调用本类的成员(变量、方法),解决成员变量和局部变量的重名问题。

    this代表所在类的引用,方法被哪个对象调用,this就代表哪个对象。

     构造方法

    构造方法就是构建、创造对象的时候,所调用的方法。

    它的作用就是用于给对象的数据(属性)进行初始化。

    构造方法的书写格式有如下特点

    • 方法名与类名相同,大小写也要一致
    • 没有返回值类型,连void都没有
    • 没有具体的返回值,不能由return带回结果数据
    • 创建对象的时候调用,每创建一次对象,不能手动调用

    以下就是一个最简单的构造方法

    // Student.java
    public class Student {
        public Student(){
            System.out.println("我是Student类的构造方法");
        }
    }
    
    // TestStudent.java
    public class TestStudent {
        public static void main(String[] args) {
            Student stu = new Student();   // 我是Student类的构造方法
        }
    }
    

    根据Student类创建出来对象的时候,就会执行Student类的构造方法。

    因为构造方法在创建对象的时候会自动调用一次,所以,我们可以让它额外帮我们初始化一下成员变量,如下就是构造方法的标准使用

    // Student.java
    public class Student {
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        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;
        }
    }
    
    // TestStudent.java
    public class TestStudent {
        public static void main(String[] args) {
            Student stu = new Student("张三",27);
            System.out.println(stu.getName() + "——" + stu.getAge());   // 张三——27
        }
    }
    

    上面代码提供了一个空参构造方法和一个有参构造方法,这样我们我们创建类的时候就可以看情况初始化对象的属性。

    构造方法也有一些注意事项,如下

    • 如果没有定义构造方法,系统将会给出一个默认的无参构造方法
    • 如果定义了构造方法,系统将不再提供默认的构造方法
    • 如果自定义了带参构造方法,还要使用无参构造方法,就必须再写一个无参数 构造方法
    • 还是建议今后无论是否使用,都手动书写无参数构造方法和带参数构造方法

    JavaBean类

    上面用于封装数据的Student类就称为JavaBean类。

  • 相关阅读:
    checkbox判断选中的三种方法
    bzoj 4031: [HEOI2015]小Z的房间
    bzoj 5056: OI游戏
    Hdoj 5181 numbers
    Loj #6164. 「美团 CodeM 初赛 Round A」数列互质
    Codeforces 869 C The Intriguing Obsession
    Loj #6142. 「2017 山东三轮集训 Day6」A
    bzoj 3714: [PA2014]Kuglarz
    Loj #6185. 烷基计数
    [HNOI2008]水平可见直线
  • 原文地址:https://www.cnblogs.com/xulinjun/p/14707869.html
Copyright © 2011-2022 走看看