跳至主要內容

类与对象

wangdx大约 18 分钟

类与对象

面向对象简介

面向对象

  面向对象是一种现在最为流行的程序设计方法,现在的程序开发几乎都是以面向对象为基础。但是在面向对象设计之前,广泛采用的是面向过程,面向过程只是针对自己来解决问题。面向过程的操作是以程序的基本功能实现为主,并不考虑实现之后就完成了项目的维护性。面向对象,更多的是要进行子模块化的设计,每一个模块都需要单独存在,并且可以被重复利用,所以,面向对象的开发更像是一个具备标准的开发式。 3 个主要特性:

  • 封装性
  • 继承性
  • 多态性

封装性

  • 封装是面向对象的方法所应遵循的一个重要原则。封装具有两个含义:一是指把对象的成员属性和行为看成一个密不可分的整体,将这两者“封装”在一个不可分割的独立单位(对象)中。另一层含义是指“信息隐蔽”,把不需要让外界知道的信息隐藏起来有些对象的属性及行为允许外界用户知道或使用,但不允许更改;而另一些属性或行为则不允许外界知晓,或者只允许使用对象的功能,而尽可能隐蔽对象的功能实现细节。
  • 封装机制在程序设计中表现为,把描述对象属性的变量与实现对象功能的方法组合在一起,定义为一个程序结构,并保证外界不能任意更改其内部的属性值,也不能任意调动其内部的功能方法。
  • 封装机制的另一个特点是,给封装在一个整体内的变量及方法规定了不同级别的“可见性”或访问权限。

继承性

  • 继承是面向对象的方法中的重要概念,是提高软件开发效率的重要手段。首先继承拥有反映事物一般特性的类;其次在其基础上派生出反映特殊事物的类。如已有汽车的类,该类中描述了汽车的普遍属性和行为,进一步再产生轿车的类,轿车的类是继承于汽车的类,轿车的类不仅拥有汽车的类的全部属性和行为,还增加轿车特有的属性和行为。
  • 在 Java 程序设计中,对于继承实现前一定要有一些已经存在的类(可以是自定义的类或者由类库所提供的类)。,用户开发的程序类需要继承这些已有的类。这样,新定义的类结构可以继承已有类的结构(属性或方法)。被继承的类称为父类或超类而经继承产生的类称为子类或派生类。根据继承机制,派生类继承了超类的所有内容,:并相应地增加了自己的一些新的成员。
  • 面向对象程序设计中的继承机制,大大增强了程序代码的可重复使用性,提高了软件的开发效率,降低了程序产生错误的可能性,也为程序的修改扩充提供了便利。
  • 若一个子类只允许继承一个父类,称为单继承;若允许继承多个父类,则称为多继承.目前 Java 程序设计语言不支持多继承。而 Java 语言通过接口(interface)的方式来弥补由于 Java 不支持多继承而带来的子类不能享用多个父类的成员的缺憾。

多态性

  • 多态是面向对象程序设计的又一个重要特征。多态是指允许程序中出现重名现象,Java 语言中含有方法重载与对象多态两种形式的多态。
    • 方法重载:在一个类中,允许多个方法使用同一个名字,但方法的参数不同,完成的功能也不同。
    • 对象多态:子类对象可以与父类对象进行相互的转换,而且根据其使用的子类的不同完成的功能也不同。
  • 多态的特性使程序的抽象程度和简洁程度更高,有助于程序设计人员对程序的分组协同开发。

类与对象概述

类与对象定义

在面向对象中类和对象是最基本、最重要的组成单元,那么什么叫类呢?类实际上是表示一个客观世界某类群体的一些基本特征抽象,属于抽象的概念集合。而对象呢?就是表示一个个具体的、可以操作的事物,例如,张三同学、李四账户、王五的汽车,这些都是可以真实使用的事物,那么就可以理解为对象,所以对象表示的是一个个独立的个体。

类与对象

例如:我们人类如果要想持续进步,那么就需要进行不断的学习,这样就需要阅读大量的图书,而图书本身就属于一个广义的抽象概念(假设每一本图书都只有书名、作者以及价格三个信息)所以图书本身就属于一个类,而后依照于此类的标准可以生产出不同内容的图书,而这些生产出来的图书就可以被所有的用户去直接使用,这个时候就可以将其称为对象,如图所示,每一个对象都拥有各自的属性内容并且共享所有图书类中定义的公共操作行为(行为可以理解为方法),例如:阅读、获取图书信息等,而这些功能都是书这个类本身所定义规范。

类与对象基本定义

类定义

类是由成员属性和方法组成的。成员属性主要定义类的一个具体信息,实际上一个成员属性就是一个变量,而方法是一些操作的行为。但是在程序设计中,定义类也是要按照具体的语法要求来完成的,例如要定义类需要使用 class 关键字定义类的定义基础语法如下。

class 类名称{
  [访问修饰符] 数据类型 成员属性(变量);
  [访问修饰符] 数据类型 成员属性(变量);
      ......
  [访问修饰符] 返回值类型 方法名称([参数类型 参数1,参数类型 参数1,...]){
    处理语句;
    [return [返回值];]
  }
}
案例
public class Book {
    String title;
    String author;
    double price;

    public void getInfo() {
        System.out.println("图书名称:" + title + "、图书作者:" + author + "、图书价格:" + price);
    }
}

对象实例化

  • 一个类定义完成后并不能够被直接使用,因为类描述的只是一个广义的概念,而具体的操作必须通过对象来执行,由于类属于 Java 引用数据类型,所以对象的定义格式如下。
    • 声明并实例化对象类名称:对象名称 = new 类名称 ();
    • 分步定义
      • 声明对象:类名称 对象名称 =null;
      • 实例化对象:对象名称=new 类名称 ();
  • 类结构调用:
    • 在 Java 中引用数据类型是需要进行内存分配的,所以在定义时必须通过关键字 new 来分配相应的内字空间后才可以使用,此时该对象也被称为“实例化对象”,而一个实例化对象就可以采用以下的方式进行类结构的操作:
      • 对象.成员属性:表示调用类之中的成员属性,可以为其赋值或者获取其保存内容;
      • 对象.方法():表示调用类之中的方法。
案例
public class Test {
    public static void main(String[] args) {
        Book book = new Book();
        book.title = "Java入门到精通";
        book.author = "王大祥";
        book.price = 99.8;
        book.getInfo();
    }
}

图书名称:Java入门到精通、图书作者:王大祥、图书价格:99.8

对象内存分析

堆栈内存

  • Java 中类属于引用数据类型,所有的引用数据类型在使用过程中都要通过关键字 new 开辟新的内存空间,当对象拥有了内存空间后才可以实现成员属性的信息保存,在引用数据类型操作中最为重要的内存有两块
    • 【heap】堆内存:保存的是对象的具体信息(成员属性),在程序之中堆内存空间的开辟是通过 new 完成的
    • 【stack】栈内存:保存的是一块堆内存的地址,即通过地址找到堆内存,而后找到对象内容,但是为了分析简化起见可以简单地理解为对象名称保存在了栈内存之中。
案例
public class Test {
    public static void main(String[] args) {
        Book book = null;
        Book book = new Book();
        book.title = "Java入门到精通";
        book.author = "王大祥";
        book.price = 99.8;
        book.getInfo();
    }
}

图书名称:Java入门到精通、图书作者:王大祥、图书价格:99.8

引用传递

对象引用传递

类是一种引用数据类型,在 Java 中引用数据类型的核心本质在于堆内存和栈内存的分配与指向处理。在程序开发中,不同的栈内存可以指向同一块的堆内存空间(相当于为同一块堆内存设置不同的对象名称),这样不同的对象就可以同时进行同一块堆内存空间的操作

案例
public class TestsDemo {
    public static void main(String[] args) {
        Book bookA = new Book();
        bookA.title = "语文";
        bookA.author = "江苏出版社";
        bookA.price = 19.65;
        Book bookB = bookA;
        bookB.title = "英文";
        bookB.author = "北京出版社";
        bookB.price = 65.25;
        bookA.getInfo();
    }
}

图书名称:英文、图书作者:北京出版社、图书价格:65.25
public class TestsDemo {
    public static void main(String[] args) {
        Book bookA = new Book();
        bookA.title = "语文";
        bookA.author = "江苏出版社";
        bookA.price = 19.65;
//        Book bookB = bookA;
//        bookB.title = "英文";
//        bookB.author = "北京出版社";
//        bookB.price = 65.25;
        changeInfo(bookA);
        bookA.getInfo();
    }
    public static void changeInfo(Book bookB){
        bookB.title = "英文";
        bookB.author = "北京出版社";
        bookB.price = 65.25;
    }
}

图书名称:英文、图书作者:北京出版社、图书价格:65.25

垃圾产生分析

范例
public class RubishDemo {
    public static void main(String[] args) {
        Book bookA = new Book();
        Book bookB = new Book();
        bookA.title = "语文";
        bookA.author = "江苏出版社";
        bookA.price = 19.65;
        bookB.title = "英文";
        bookB.author = "北京出版社";
        bookB.price = 65.25;
        bookB = bookA;
        bookB.title = "体育";
        bookB.price = 35.25;
        bookA.getInfo();
    }
}

图书名称:体育、图书作者:江苏出版社、图书价格:35.25

成员属性封装

属性封装

面向对象的第一大特性指的就是封装性,而封装性最重要的特点就是内部结构对外不可见。在之前的操作中可以发现所有类中的成员属性都可以直接通过实例化对象在类的外部进行调用,而这样的调用是不安全的,那么此时最稳妥的做法就是利用 private 实现成员属性的封装处理。而一旦使用了 private 封装之后,是不允许外部对象直接访问成员属性的,而此时的访问则需要按照 Java 的开发标准定义 setter()、getter()方法处理。

  • setter 方法(以“private String title”属性为例):public void setTitle(String t)
  • getter 方法(以“private String title”属性为例):public String getTitle()
范例
public class BookF {
    private String title;
    private String author;
    private double price;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public void getInfo() {
        System.out.println("图书名称:" + title + "、图书作者:" + author + "、图书价格:" + price);
    }
}

class TestBookF {
    public static void main(String[] args) {
        BookF bookF = new BookF();
        bookF.setAuthor("李兴华");
        bookF.setTitle("Java从入门到实战");
        bookF.setPrice(99.8);
        bookF.getInfo();
    }
}

图书名称:Java从入门到实战、图书作者:李兴华、图书价格:99.8

构造方法

定义

构造方法是在类中定义的一种特殊方法,它在一个类使用关键字 new 实例化新对象时默认调用,其主要功能是完成对象属性的初始化操作,在 ava 语言中,类中构造方法的定义要求如下。

  • 构造方法是实例化对象时进行调用的,所以构造方法的名称要与类名称保持一致
  • 构造方法区别与普通方法,所以构造方法不允许有返回值类型声明

默认构造方法

在一个类中至少都会存在一个构造方法,在之前所编写的程序中实际上并没有声明构造方法,那么当使用 javac 命令编译程序时就会自动为类追加一个无参且无返回值的构造

范例
源代码
class Book{}
编译后classclass Book{
  public Book(){}
}
/**
 * 构造方法为属性初始化
 * @author wangdx
 */
public class BookCon {
    private String title;
    private String author;
    private double price;

    public BookCon(String title1, String author1, double price1) {
        title = title1;
        author = author1;
        price = price1;
    }

    public void getInfo() {
        System.out.println("图书名称:" + title + "、图书作者:" + author + "、图书价格:" + price);
    }
}
class BookConTest{
    public static void main(String[] args) {
        BookCon bookCon = new BookCon("Java从入门到实战","李兴华",99.8);
        bookCon.getInfo();
    }
}
/**
 * 构造方法重载
 * @author wangdx
 */
public class BookRel {
    private String title;
    private String author;
    private double price;

    public BookRel() {
    }

    public BookRel(String title1) {
        title = title1;
        author = "沐言科技";
        price = -1.0;
    }

    public BookRel(String title, String author, double price) {
        this.title = title;
        this.author = author;
        this.price = price;
    }

    public void getInfo() {
        System.out.println("图书名称:" + title + "、图书作者:" + author + "、图书价格:" + price);
    }
}

class BookRelTest {
    public static void main(String[] args) {
        BookRel bookRel = new BookRel("Java入门到实战");
        bookRel.getInfo();
    }
}

图书名称:Java入门到实战、图书作者:沐言科技、图书价格:-1.0

匿名对象

匿名对象结构

在对象实例化定义格式中,关键字 new 的主要功能是进行堆内存空间的开辟,而对象的名称是为了对该堆内存的引用,这样不仅方便使用堆内存同时防止其变为垃圾空间,也就是说对象真正的内容是在堆内存里面,而有了构造方法之后就可以在堆内存开辟的同时进行对象实例化处理,这样即便没有栈内存指向,该对象也可以使用一次,而对于这种没有指向的对象就称为匿名对象

范例
/**
 * 匿名对象操作类结构
 *
 * @author wangdx
 */
public class BookNm {
    private String title;
    private String author;
    private double price;

    public BookNm(String title, String author, double price) {
        this.title = title;
        this.author = author;
        this.price = price;
    }

    public void getInfo() {
        System.out.println("图书名称:" + title + "、图书作者:" + author + "、图书价格:" + price);
    }
}

class BookNmTest {
    public static void main(String[] args) {
        new BookNm("Java从入门到实战", "李兴华", 99.8).getInfo();
    }
}

图书名称:Java从入门到实战、图书作者:李兴华、图书价格:99.8

调用本类成员属性

当通过 setter()或者是构造方法为类中的成员设置内容时,为了可以清楚地描述出具体参数与成员属性的关系,往往会使用同样的名称,那么此时就需要通过 this 来描述类的成员属性。

范例
public class BookNm {
    private String title;
    private String author;
    private double price;

    public BookNm(String title, String author, double price) {
        this.title = title;
        this.author = author;
        this.price = price;
    }

    public void getInfo() {
        System.out.println("图书名称:" + title + "、图书作者:" + author + "、图书价格:" + price);
    }
}

调用本类普通方法

本类方法互调用

在一个类中往往会存在有大量的方法,按照面向对象的传统要求,所有类中定义的方法都必须通过实例化对象的形式才可以进行调用,而在一个类的内部当需要这些普通方法互相调用前也可以明确的使用“this.方法()”的形式调用。

范例
  public class BookF {
    private String title;
    private String author;
    private double price;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public void getInfo() {
        System.out.println("图书名称:" + this.getTitle() + "、图书作者:" + this.getAuthor() + "、图书价格:" + this.getPrice());
    }
}

构造方法互调用

一个类之中构造方法是允许进行重载的,,在进行构造方法重载的过程之中只需要考虑方法的参数类型及个数的不同即可,所以一个类里面构造方法可能有很多,那么在这样的环境下就可以考虑利用“this()”的语法形式实现同一类中构造方法的互相调用。

范例
public class BookRel {
    private String title;
    private String author;
    private double price;

    public BookRel() {
        System.out.println("对象实例化 xxx");
    }

    public BookRel(String title1) {
        this();
        title = title1;
    }

    public BookRel(String title, String author, double price) {
        this(title);
        this.author = author;
        this.price = price;
    }

    public void getInfo() {
        System.out.println("图书名称:" + title + "、图书作者:" + author + "、图书价格:" + price);
    }
}

class BookRelTest {
    public static void main(String[] args) {
       new BookRel("Pathy入门到实战","李老哥",99.8);
       new BookRel("Pathy入门到实战");
       new BookRel();
    }
}

当前对象 this

范例
public class BookThis {
    public void print() {
        System.out.println("print()==" + this);
    }
}

class ThisTest {
    public static void main(String[] args) {
        BookThis bookThis = new BookThis();
        System.out.println("[main]bookThis=" + bookThis);
        bookThis.print();
        BookThis bookThisB = new BookThis();
        System.out.println("[main]bookThisB=" + bookThisB);
        bookThisB.print();
    }
}

[main]bookThis=classobj.BookThis@66d33a
print()classobj.BookThis@66d33a
[main]bookThisB=classobj.BookThis@7cf10a6f
print()classobj.BookThis@7cf10a6f

内存分析

传递当前对象引用

详情
package classobj;

/**
 * @author wangdx
 */
public class Message {
    private String title;
    private String content;
    private Channel channel;

    public Message(String title, String content, Channel channel) {
        this.title = title;
        this.content = content;
        this.channel = channel;
    }

    public void send() {
        if (this.channel.connect()) {
            System.out.println("[Message]消息发送,消息标题:" + this.title + "、消息内容:" + this.content);
            this.channel.close();
        } else {
            System.out.println("[Error]灭有可用的消息发送通道,消息发送失败。。。");
        }
    }
}

class Channel {
    private Message message;

    public Channel(String title, String content) {
        this.message = new Message(title, content, this);
        this.message.send();
    }

    public boolean connect() {
        System.out.println("[Channel]建立消息的发送通道。。。");
        return true;
    }

    public void close() {
        System.out.println("[Channel]关闭消息通道。。。");
    }
}

class MessageTest {
    public static void main(String[] args) {
        new Channel("沐言科技", "www.yootk.com");
    }
}

[Channel]建立消息的发送通道。。。
[Message]消息发送,消息标题:沐言科技、消息内容:www.yootk.com
[Channel]关闭消息通道。。。

简单 Java 类

简单 java 类指的是可以描述某一类信息的程序类,例如:描述个人信息、描述书信息.描述部门信息等,并且在这个类之中并没有特别复杂的逻辑操作,只作为一种信息保存的媒介存在,以之前定义的图书类(Book)为例可以发现其组成简单,只是为了描述出图书的相关信息

简单 Java 类开发要求

  • 类名称一定要有意义,可以明确的描述某一类事物;
  • 类之中的所有属性都必须使用 private 进行封装,封装后的属性必须要提供有 setter、getter 方法;
  • 类之中可以提供有无数多个构造方法,但是必须要保留有无参构造方法
  • 类之中不允许出现任何的输出语句,所有内容的获取必须返回;
  • 【可选】可以提供有一个获取对象详细信息的方法,暂时将此方法名称定义为 getnfo()
范例
public class Dept {
    private long deptNO; //编码
    private String name; //名称
    private String loc; //位置

    public Dept() {
    }

    public Dept(long deptNO, String name, String loc) {
        this.deptNO = deptNO;
        this.name = name;
        this.loc = loc;
    }

    public long getDeptNO() {
        return deptNO;
    }

    public void setDeptNO(long deptNO) {
        this.deptNO = deptNO;
    }

    public String getName() {
        return name;
    }

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

    public String getLoc() {
        return loc;
    }

    public void setLoc(String loc) {
        this.loc = loc;
    }
}

static 属性

static 关键字

在一个类中,主要的组成就是属性和方法(分为构造方法与普通方法两种),而每一个对象都分别拥有各自的属性内容(不同对象的属性保存在不同的堆内存中)。如果想要类中的某个属性定义为公共属性(所有对象都可以使用的属性),则可以在声明属性前加上 static 关键字。

范例
public class Book {
    private String title;
    private String author;
    private double price;
    static String pub = "沐言出版社";

    public Book(String title, String author, double price) {
        this.title = title;
        this.author = author;
        this.price = price;
    }

    public String getInfo() {
        return "图书名称:" + this.title + "、图书作者:" + this.author + "、图书价格:" + this.price + "、出版社:" + this.pub;
    }
}

class BookTest {
    public static void main(String[] args) {
        Book bookA = new Book("入门到实战", "李兴华", 99.8);
        Book bookB = new Book("Spring开发实战", "李兴华11", 991.8);
        Book.pub = "北京出版社";
        System.out.println(bookB.getInfo());
        System.out.println(bookA.getInfo());
    }
}

图书名称:Spring开发实战、图书作者:李兴华11、图书价格:991.8、出版社:北京出版社
图书名称:入门到实战、图书作者:李兴华、图书价格:99.8、出版社:北京出版社

static 应用案例

统计实例化对象个数

范例
public class Book {
    private static int count = 0;

    public Book() {
        Book.count++;
        System.out.println("当前实例化对象个数:" + Book.count);
    }
}

class Test {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            new Book();
        }
    }
}

当前实例化对象个数:1
当前实例化对象个数:2
当前实例化对象个数:3

static 方法

类中的普通方法实际上就分为了两种:static 方法和非 static 方法,而这两类方法之间的调用也存在着以下的限制

  • static 定义的方法不能调用非 static 的方法或属性.
  • 非 static 定义的方法可以调用 static 的属性或方法,

普通代码块

if(true){

}
普通代码块
{

}

构造块

class Book{
  {
    String title = "沐言科技";
    title = title +"www.yootk.com";
    System.out.println("[构造块]" + Book.count);
  }
}

静态代码块

static 代码块

静态代码块也是定义在类中的,如果一个构造代码块上使用了 static 关键字进行定义的话,那么就表示静态代码块,静态代码块要考虑两种情况。

  • 情况 1:在非主类中定义的静态代码块。
  • 情况 2:在主类中定义的静态代码块。
范例

上次编辑于: