Java 面向对象

理解面向对象

  • 面向对象是相对面向过程而言。
  • 面向对象和面向过程都是一种思想。
  • 面向过程
    • 强调的是功能行为
  • 面向对象
    • 将功能封装进对象,强调具备了功能的对象。
  • 面向对象是基于面向过程的。

面向对象的特点

  • 面向对象三个特征:封装,继承,多态。
  • 以后开发:其实就是找对象使用 ,没有对象,就常见对象。
  • 找对象,建立对象,使用对象,维护对象的关系。

类与对象的关系

  • 实际生活中的对象:张三,李四。
  • 想要描述:提取对象中共性内容,对象具体的抽象。
  • 描述时:这些对象的共性有:名称,年龄,性别。
  • 映射到java中,描述就是class定义的类。
  • 具体对象就是对应java在堆内存中用new建立实体。
  • 类:对象现实生活事物的描述。
  • 对象:就是这类的事物,实实在在存在个体。
// 需求: 描述汽车(颜色和轮胎数)。描述事物其实就时事物的属性和行为。
class Car {
    // 描述颜色
    String color = "红色";
    // 描述轮胎数
    int num = 4;

    // 运行行为
    void run() {
        System.out.println("颜色:" + color + ", 轮胎数:" + num);
    }
}

public class Main {
    public static void main(String[] args) {
        // 生产汽车,在java中通过new操作符来完成。
        // 其实就是在堆内存产生一个实体。
        Car c = new Car(); // c 就是一个类类型变量。记住:类类型变量指向对象。
        // 需求:将现有车的颜色改成蓝色,指挥改对象做使用,在java指挥方法是:对象,对象成员。
        c.color = "蓝色";
        c.run();
    }
}

成员变量和局部变量

作用范围

  • 成员变量作用与整个类中。
  • 局部变量作用与函数中,或者语句中。

内存位置

  • 成员变量:内存中,因为对象的存在,才在内存中存在。
  • 局部变量:存在栈内存中。

匿名对象

  • 匿名对象是对象的简化形式。
  • 匿名对象两种使用情况
    • 当对象方法仅进行一次调用时。
    • 匿名对象可以作为实际参数进行传递。
class Car {
    String color = "红色";
    int num = 4;

    void run() {
        System.out.println("颜色:" + color + ", 轮胎数:" + num);
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建一个Car对象color设置为蓝色
        new Car().color = "蓝色";
        // 创建一个新的Car对象num设置为6.
        new Car().num = 6;
        // 创建一个新的Car对象调用run方法。
        new Car().run();
    }
}

封装

  • 封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
  • 好处:
    • 就变化隔离。
    • 便于使用。
    • 提高重用性。
    • 提高安全性。
  • 封装原则:
    • 将不需要对外提供的内容都隐藏起来。
    • 把属性都隐藏,提供公共方法对其访问。
class Person {
    /*   private: 私有,权限修饰符以后,用于修饰符类中的成员(成员变量,成员函数),私有只在本类中有效。
         将age私有化以后,类以外即使建立了对象也不能直接访问。
         但是人应该有年龄,就需要在Person类中提供对应访问age的方法。
         注意:私有仅仅是封装的一种表现形式。
         之所以对外提供访问方式,就因为可以在访问方法中加入逻辑判断等语句。
         对访问的数据进行操作,提高代码的健壮性。 */
    private int age;

    public void setAge(int a) {
        if (a > 0 && a < 130) {
            age = a;
            speak();
        }else {
            System.out.println("error age");
        }
    }

    public int getAge() {
        return age;
    }

    void speak() {
        System.out.println("age = " + age);
    }
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person();
        person.setAge(18);
        person.speak();
    }
}

构造函数

特点:

  • 函数名与类名相同。
  • 不用定义返回值类型。
  • 不可以学return语句。

作用:

  • 给对象进行初始化。

注意:

  • 默认构造函数的特点。
  • 多个构造函数是以重载的形式存在。
class Person {
    /*对象一建立就会调用与子对应的构造函数。
    构造函数的作用:可以用于给对象进行初始化。

    构造函数的小细节:
    当在类中自定义了构造函数后,默认的构造函数就没有了。*/

    private String name;
    private int age;

    public Person() {
        System.out.println("A:'name'=" + name + ", " + "'age'=" + age);
    }

    public Person(String name) {
        System.out.println("B:'name'=" + name + ", " + "'age'=" + age);
    }

    public Person(String name, int age) {
        System.out.println("C:'name'=" + name + ", " + "'age'=" + age);
    }
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person();
        Person person1 = new Person("张三");
        Person person2 = new Person("李四", 18);
    }
}

构造函数和一般函数区别

  • 在运行上也有不同。
  • 构造函数是在对象一建立就运行,给对象初始化。
  • 而一般方法是对对象调用才执行,给是对象添加对象具备的功能。
  • 一个对象建立,构造函数只运行一次。
  • 而一般方法可以被该对象调用多次。

构造代码块

作用:

  • 给对象进行初始化。
  • 对象一建立就运行,而且优先于构造函数执行。

区别:

  • 构造代码块是给所有对象进行统一初始化。
  • 而构造函数是给对应的对象初始化。
class Person {

    private String name;
    private int age;

    {
        System.out.println("啊,我被创建了");
    }

    public Person() {
        System.out.println("A:'name'=" + name + ", " + "'age'=" + age);
    }

    public Person(String name) {
        System.out.println("B:'name'=" + name + ", " + "'age'=" + age);
    }

    public Person(String name, int age) {
        System.out.println("C:'name'=" + name + ", " + "'age'=" + age);
    }
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person();
        Person person1 = new Person("张三");
        Person person2 = new Person("李四", 18);
    }
}

输出结果

啊,我被创建了
A:'name'=null, 'age'=0
啊,我被创建了
B:'name'=张三, 'age'=0
啊,我被创建了
C:'name'=李四, 'age'=18

this关键字

this 在java中,这是一个引用当前对象的引用变量。

class Person {
/*    this:看上去,是用于区分局部变量和成员变量同名情况。
    this:为什么可以解决这个问题?
    this:到底代表的是什么?

    this:就代表本类的对象,到底代表哪一个呢?
    this:代表它所在函数属于对象的引用。
    哪个对象在调用this所在的函数,this就代表哪个对象。*/
    private String name;
    private int age;

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person();
        person.setAge(10);
        System.out.println(person.getAge());
    }
}

static关键字

  • static关键字:
    • 用于修饰成员(成员变量和成员函数)
  • 被修饰后的成员具备以下特点:
    • 随着类的加载而加载
      • 也就是说:静态随着类的消失而消失。说明它的生命周期最长。
    • 优先于对象存在
    • 被所有对象所共享
    • 可以直接被类名调用
class Person {
    String name;
    static String country = "CN";

    public static void show() {
        System.out.println("country=" + country);
    }
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(Person.country);
        Person.show();
    }
}

实例变量和变量区别:

  • 存放位置。
    • 类变量随着类的加载而在于方法区中。
    • 实例变量随着对象的建立而存在在于内存堆中。
  • 生命周期:
    • 类变量的生命周期最长,随着类的消失而消失。
    • 实例变量生命周期随着对象的消失而消失。

使用注意:

  • 静态方法只能访问静态成员
    • 非静态方法既可以访问静态也可以访问非静态。
  • 静态方法中不可以写this,super关键字
    • 因为静态优先于对象存在,所以静态方法中不可以出现this。
  • 主函数是静态的
    • public static void main(String[] args) 主函数:是一个特殊的函数,作为程序的入口,可以被jvm调用。
    • 主函数的定义:
      • public:代表着该函数访问权限最大的。
      • static:代表着函数随着类加载就已经存在了。
      • void:代表主函数没有具体的返回值。
      • main:不是关键字,但是是一个特殊单词,可以别jvm识别。
      • (String[] args) :函数的参数,参数类型是一个数组,该数组中的元素是字符串。字符串类型的数据。
    • 主函数是固定的格式:jvm识别。
    • jvm在调用主函数时,传入的是new String[0];

静态有利也有弊

  • 利处:对对象的共享数据进行单 独空间的存储,节省空间,没有必要每一个对象中存储一份,可以直接被类名调用。
  • 弊端:生命时间过长。访问出现局限性。(静态虽好,只能访问静态。)

什么使用静态?

要从两方面下手:

因为静态修饰的内容有成员变量和函数。

什么时候定义静态变量(类变量)呢?

当对象中出现共享数据时,该数据被静态所修饰。

对象中的特有数据要定义成非静态存在于堆内存中。

什么时候定义静态函数?

当功能内部没有访问到静态数据(对象的特有数据)。

那么该功能可以定义成静态的。

静态代码块

// 格式
static  {
   // 静态代码中执行语句
}

特点:

  • 随着类的加载而执行,只执行一次,并优先于主函数。
  • 用于给类进行初始化。

单例设计模式

设计模式:解决某一类问题最行之有效的方法。

java中23种设计模式:

单例设计模式:解决一个类在内存只存在一个对象。

  • 想要保住对象唯一。
    • 为了避免其他程序过多建立该对象,先禁止其他程序建立该对象。
    • 还为了让其他程序可以访问到该对象,只好在本类中,自定义一个对象。
    • 为了方便其他程序对自定义对象的访问,可以对外提供一些访问方法。
  • 这三步怎么用代码体现?
    • 将构造函数私有化。
    • 在类中创建一个本地类对象。
    • 提供一个方法可以获取到该对象。

对于事物该怎么描述,还怎么描述。

当要将该事物的对象保证在内存中唯一是,就将以上三步加上即可。

// 第一种:这种是先初始化对象
// 称为:饿汉式。
// 类一进内存,就已经创建好了对象。
class Person {
    int age = 0;

    public Person() {
    }

    protected static final Person P = new Person();

    public static Person getInstance() {
        return P;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

// 第二种:对象是方法被调用时,才初始化,也叫做对象的延迟加载,
// 称为:懒汉式。
// 类进内存,对象还没有存在,只有调用getInstance方法时,才建立对象。

class Single {
    int age = 0;
    protected static Single s = null;

    private Single() {
    }

    public static Single getInstance() {
        if (s == null) {
            synchronized (Single.class) {
                if (s == null) s = new Single();
            }
        }
        return s;
    }


    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

public class Main {
    public static void main(String[] args) {
        // 饿汉式
        Person.getInstance().setAge(18);
        System.out.println(Person.getInstance().getAge());
        Person.getInstance().setAge(20);
        System.out.println(Person.getInstance().getAge());
        // 懒汉式
        Single.getInstance().setAge(10);
        System.out.println(Single.getInstance().getAge());
        Single.getInstance().setAge(15);
        System.out.println(Single.getInstance().getAge());
    }
}
// 定义单例,建议使用饿汉式。

输出结果

18
20
10
15