2 Java面向对象编程 类

2、面向对象简介

Java语言最大特点:面向对象编程设计
面向过程:C语言,面对一个问题的解决方案
面向对象:C++/Java,模块化设计,进行重用配置,考虑标准

1、面向对象三个主要特征:
封装性:内部操作对外部不可见
继承性:已有结构的基础上继续进行功能扩充
多态性:是在继承性的基础上扩充而来的概念,指类型的转换处理

2、面向对象开发三个步骤:
OOA:面向对象分析
OOD:面向对象设计
OOP:面向对象编程

3、类与对象

类:对某一类事物共性的抽象
对象:描述一个具体的产物

类是一个模型,对象是类可以使用的实例
先有类再有对象

类的组成:
成员属性Field 简称属性
操作方法Method 对象的行为

4、类与对象的定义及使用

Java中,类是一个独立的结构体

属性就是变量
方法就是可以重复执行的代码

// 定义类
class Person {
    // 定义属性
    String name;  // 引用数据类型 默认值 null
    int age;      // 基础数据类型 默认值 0

    // 定义方法
    public void tell(){
        System.out.println("姓名:" + this.name + " 年龄:" + this.age);
    }

    public static void main(String[] args) {
        Person person = new Person();
        person.name = "张三";
        person.age = 18;
        person.tell();
        // 姓名:张三 年龄:18
    }

}

生产对象两种方式:
1、声明并实例化对象
类名称 对象名称 = new 类名称();

2、分步完成
(1)声明对象:类名称 对象名称 = null;
(2)实例化对象:对象名称 = new 类名称();

实例化对象调用操作:
调用属性:实例化对象.成员属性;
调用方法:实例化对象.方法名称();

5、内存对象分析

最常用的2块内存空间
堆内存:保存对象具体信息 new开辟堆内存空间
栈内存:保存一块堆内存地址

/**
栈内存              堆内存     
地址Ox0001    ->   对象内容
*/


// 方式一
Person person = new Person();


// 方式二
Person person = null;
person = new Person();

所有的对象在调用属性或方法之前,必须实例化

6、对象引用分析

同一块堆内存可以被不同的栈内存所指向,也可以更换指向

修改person2, person1也会被修改

Person person1 = new Person();
person1.name = "张三";
person1.age = 19;

Person person2 = person1;
person2.tell();
// 姓名:张三 年龄:19

引用传递可以发生在方法调用

public static void main(String[] args) {
    Person person = new Person();
    person.name = "张三";
    person.age = 18;

    change(person); // 相当于: Person temp = person;

    person.tell();
    // 姓名:李四 年龄:18
}

public static void change(Person temp){
    temp.name = "李四";
    // 方法结束后断开引用
}

7、引用于垃圾产生分析

垃圾空间:没有任何栈内存指向的堆内存空间
垃圾会被GC(Garbage Collector)垃圾收集器定期回收
垃圾过多会影响GC性能

一个栈内存只能保存有一个堆内存的地址数据

Person person1 = new Person(); // Ox0001
Person person2 = new Person(); // Ox0002

person2 = person1;   // 此时 person2 指向的 Ox0002 对象成为了垃圾

8、成员属性封装

封装:对数据进行保护

private关键字对外不可见
使用setter、getter设置或获取属性

类中的所有属性都必须使用private封装,需要提供setter、getter方法

class Person {

    // 私有化属性
    private String name; 

    // 对外提供geter, setter方法
    public void setName(String n){
        name = n;
    }

    public String getName(){
        return name;
    }

    public static void main(String[] args) {
        Person person = new Person();
        person.setName("张三");
        System.out.println(person.getName());
        // 张三
    }
}

9、构造方法与匿名对象

现有程序使用类,经过了2个步骤:
1、声明实例化对象,只能使用默认值
2、通过 setter 方法设置属性

构造方法: 实例化对象时进行数据初始化
1、构造方法名与类名必须一致
2、构造方法无返回值
3、构造方法在new实例化对象时自动调用

class Person {

    // 私有化属性
    private String name; 

    // 有参构造方法
    public Person(String n){
        name = n;
    }

    public static void main(String[] args) {
        Person person = new Person("张三");
        System.out.println(person.getName());
        // 张三
    }
}

(1)Person 定义对象所属类型,类型决定可以调用的方法
(2)person 实例化对象的名称
(3)new 开辟新的堆内存空间
(4)Person("张三") 调用构造函数(有参,无参)

所有的类都会提供有无参构造方法,程序编译时自动创建,如果明确构造方法则不自动创建

结论:一个类至少存在一个构造方法

问题:构造方法没有返回值?不使用void

构造方法与普通方法区别:
构造方法在类对象实例化时调用
普通方法在类对象实例化之后调用

构造方法重载
只用考虑方法签名(参数个数,类型,顺序)
按照参数数量顺序排列构造方法

class Person {

    // 私有化属性
    private String name; 

    // 无参构造方法
    public Person(){
    }

    // 有参构造方法
    public Person(String n){
        name = n;
    }

    public String getName(){
        return name;
    }

    public static void main(String[] args) {
        Person person = new Person("张三");
        System.out.println(person.getName());
        // 张三
    }
}

匿名对象

new Person("张三").getName());
// 张三

使用一次后就会被GC回收释放

方法可以传递基本数据类型和引用数据类型

10、this调用本类属性

三类描述
1、当前类中的属性 this.属性
2、当前类中的方法(构造方法:this()、普通方法:this.方法())
3、描述当前对象

访问本类中的属性一定要加this

public Person(String name, int age){
    this.name = name ;
    this.age = age ;
}

11、this调用本类方法

1、调用普通方法

setName(name) ;

// 或者

this.setName(name) ;

好的代码:
代码结构可以重用
没有重复代码

2、调用构造方法
this()
必须在实例化新对象的时候调用
只允许放在构造函数首行
相互调用必须有出口

// 无参构造方法
public Person(){
    this("张三");
}

// 有参构造方法
public Person(String name){
    this.name = name;
}

构造方法调用实现默认参数

class Person {

    // 私有化属性
    private String name; 
    private int age;

    // 无参构造方法
    public Person(){
        this("张三");
    }

    // 一参构造方法
    public Person(String name){
        this(name, 21);
    }

    // 两参构造方法
    public Person(String name, int age){
        this.name = name;
        this.age = age ;
    }

    public void getInfo(){
        System.out.println("name: " + this.name + " age: " + this.age);
    }


    public static void main(String[] args) {
        new Person().getInfo();
        new Person("李四").getInfo();
        new Person("王五", 22).getInfo();
        /*
        name: 张三 age: 21
        name: 李四 age: 21
        name: 王五 age: 22
        */
    }
}

12、综合实战:简单Java类

简单Java类:
可以描述某一类信息的程序类,没有特别复杂的操作,只作为一种信息存储的媒介

核心结构
1、类名有意义,明确描述某一类事物
2、属性必须使用private封装,提供setter、getter
3、可以提供多个构造方法,必须保留无参构造方法
4、不允许有任何输出,内有获取必须返回

非必须:
1、可以提供获取对象详细信息方法,getInfo()

涉及概念
数据类型、类的定义、private封装、方法定义、对象实例化

class Person {

    // 私有化属性
    private String name; 
    private int age;

    // 无参构造方法
    public Person(){
        this("张三", 23);
    }

    // 两参构造方法
    public Person(String name, int age){
        this.name = name;
        this.age = age ;
    }

    // setter getter
    public void setName(String name){
        this.name = name;
    }

    public String getName(){
        return this.name ;
    }

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

    public int getAge(){
        return this.age ;
    }

    public String getInfo(){
        return "name: " + this.name + " age: " + this.age;
    }

    public static void main(String[] args) {
        System.out.println(new Person("王五", 22).getInfo());
        // name: 王五 age: 22
    }
}

13、声明static属性

static修饰的属性为公共属性,一个对象修改,所有对象都会被修改
应该由类来进行访问,而不是对象,可以由类名来调用
static 属性不受类实例化限制,不实例化也可以调用
进行类设计时首选非static属性,涉及公共信息才使用static

全局数据区        栈内存      堆内存
static 数据      person1   ->  {name, age}
                person1   ->  {name, age}
class Person {
    String name; 
    static String country;

    public Person(String name){
        this.name = name;
    }

    public static void main(String[] args) {
        Person person1 = new Person("张三");
        Person person2 = new Person("李四");

        Person.country = "中国";
        System.out.println(person1.country);
        System.out.println(person2.country);
        // 中国   中国
    }
}

14、声明static方法

static方法只允许调用static属性或static方法
static属性和方法都可以在没有实例化对象的前提下使用

应用场景:
回避实例化对象调用并且描述公共属性的情况

15、static应用案例

实现实例化对象个数统计

class Person {

    static int count;

    public Person(){
        count ++;
        System.out.println("第 " + count + " 个实例");
    }

    public static void main(String[] args) {
        new Person();
        new Person();
        new Person();
        /*
        第 1 个实例
        第 2 个实例
        第 3 个实例
        */
    }
}

16、普通代码块

代码块:由"{}"定义的结构

分类:
1、普通代码块
2、构造代码块
3、静态代码块
4、同步代码块(多线程)

普通代码块
定义在方法中的代码块

// 普通代码块
{
    int age = 12;
    System.out.println(age);  // 12
}

int age = 15;
System.out.println(age);  // 15

17、构造代码块

构造块优先于构造方法执行,每次实例化都会调用构造代码块

class Person {
    public Person(){
        System.out.println("构造方法");
    }

    {
        System.out.println("构造代码块");
    }

    public static void main(String[] args) {
        new Person();
        new Person();
        /**
        构造代码块
        构造方法
        构造代码块
        构造方法
        */
    }
}

18、静态代码块

static关键字定义的代码块
静态代码块优先于构造函数执行,不管实例化多少次只会执行一次
主要目的是为了静态属性初始化

静态代码块优先于主方法先执行

class Person {
    public Person(){
        System.out.println("构造方法");
    }

    {
        System.out.println("构造代码块");
    }

    static {
        System.out.println("静态代码块");
    }

    public static void main(String[] args) {
        System.out.println("主方法代码块");
        new Person();
        new Person();
        /**
        静态代码块
        主方法代码块
        构造代码块
        构造方法
        构造代码块
        构造方法
        /
    }
}

19、案例分析一(Address)

实现一个地址类,包含国家,省份,城市,街道,邮政编码

实现一个简单java类

class Address {
    private String country;
    private String province;
    private String city;
    private String street;
    private String zipcode;

    // setter
    public void setCountry(String country){
        this.country = country;
    }

    public void setProvince(String province){
        this.province = province;
    }

    public void setCity(String city){
        this.city = city;
    }

    public void setStreet(String street){
        this.street = street;
    }

    public void setZipcode(String zipcode){
        this.zipcode = zipcode;
    }

    // getter
    public String getCountry(){
        return this.country;
    }

    public String getProvince(){
        return this.province;
    }

    public String getCity(){
        return this.city;
    }

    public String getStreet(){
        return this.street;
    }

    public String getZipcode(){
        return this.zipcode;
    }

    // info
    public String getInfo(){
        return "国家: " + this.country +
               ", 省份: " + this.province + 
               ", 城市: " + this.city + 
               ", 街道: " + this.street + 
               ", 邮政编码: " + this.zipcode;
    }

    public Address(String country, String province, String city, String street, String zipcode){
        this.country = country;
        this.province = province;
        this.city = city;
        this.street = street;
        this.zipcode = zipcode;
    }


    public static void main(String[] args) {
        Address address = new Address("中国", "北京", "朝阳", "大望路", "10001");
        System.out.println(address.getInfo());
        // 国家: 中国, 省份: 北京, 城市: 朝阳, 街道: 大望路, 邮政编码: 10001

    }
}

20、案例分析二(Employee)

实现一个员工类,包含编号,姓名,薪水,税率,还包括薪水增长计算和增长后的工资

class Employee{
    private long no;
    private String name;
    private double salary;
    private double rate;

    // setter getter ...

    public String getInfo(){
        return "编号:" + this.no + 
                ", 姓名: " + this.name + 
                ", 薪水 " + this.salary + 
                ", 涨幅: " + this.rate; 
    }

    public void increaseSalary(){
        this.salary = this.salary * (1 + this.rate);
    }

    public Employee(long no, String name, double salary, double rate){
        this.no = no;
        this.name = name;
        this.salary = salary;
        this.rate = rate;
    }

    public static void main(String[] args){
        Employee employee = new Employee(1L, "张三", 3000.0, 0.3);
        System.out.println(employee.getInfo());
        // 编号:1, 姓名: 张三, 薪水 3000.0, 涨幅: 0.3

        employee.increaseSalary();
        System.out.println(employee.getInfo());
        // 编号:1, 姓名: 张三, 薪水 3900.0, 涨幅: 0.3
    }

}

21、案例分析三(Dog)

创建Dog类,有名字,颜色,年龄,定义构造方法初始化属性

class Dog{
    private String name;
    private String color;
    private int age;

    // getter setter

    public Dog(String name, String color, int age){
        this.name=name;
        this.color=color;
        this.age=age;
    }

    public static void main(String[] args) {
        Dog dog = new Dog("小黑", "黑色", 2);
    }

}

22、案例分析四(Account)

定义银行账户类,包括
1、数据:账户名称,账户余额
2、方法:开户(设置账号,余额),利用构造方法完成
3、查询余额

class Account{
    private String name;
    private double balance;

    public Account(String name){
        this(name, 0.0);
    }

    public Account(String name, double balance){
        this.name = name;;
        this.balance = balance;;
    }

    // 查询余额
    public double getBalance(){
        return this.balance;
    }

    public static void main(String[] args) {
        Account account = new Account("张三", 2000.0);
        System.out.println(account.getBalance());
        // 2000.0
    }
}

23、案例分析五(User)

创建用户类
1、用户名,记录用户个数
2、获取用户数

class User{
    private String name;

    private static int count = 0;

    public User(String name){
        this.name = name;
        count++;
    }

    public static int getCount(){
        return count;
    }

    public static void main(String[] args) {
        User user1 = new User("小明");
        User user2 = new User("小红");
        User user3 = new User("小花");

        System.out.println(User.getCount());
        // 3

    }
}

24、案例分析六(Book)

创建图书类
数据:书名,价格,编号(利用静态数据实现自动编号)
方法:统计总数

class Book{
    private int uid;
    private String name;
    private double price;
    private static int count = 0;

    public Book(String name, Double price){
        count++;
        this.uid = count;
        this.name = name ;
        this.price = price ;
    }

    public String getInfo(){
        return "<"+ this.uid + "> <<" + this.name +">> "+ this.price;
    }

    public static int getCount(){
        return count;
    }

    public static void main(String[] args) {
        Book book1 = new Book("今日头条", 12.0);
        Book book2 = new Book("百度", 14.0);
        Book book3 = new Book("腾讯", 11.0);

        System.out.println(Book.getCount()); 
        // 3

        System.out.println(book3.getInfo());
        // <3> <<腾讯>> 11.0
    }
}