Java_4 类和对象

1.面向对象概述

面向对象思想是人类最自然的一种思考方式,它将所有预处理的问题抽象为对象,同时了解这些对象具有哪些相应的属性以及展示这些对象的行为,以解决这些对象面临的一些实际问题,这样就在程序开发中引入了面向对象设计的概念,面向对象的实质就是对现实世界的对象进行建模操作。

1.1 什么是对象

现实世界中,随处可见的一种事物就是对象,对象是事物存在的实体。通常会将对象划分为两部分,即动态部分与静态部分。静态部分即是“属性”,任何对象都会具备其自身属性,对象所具有的行为(动态部分)即为方法。

1.2 什么是类

类是同一类事物的统称,如果将现实世界中的一个事物抽象成对象,类就是这类对象的统称。

类是封装对象的属性和行为的载体,反过来说具有相同的属性和行为的一类实体被称为类。

在Java语言中,类中对象的行为是以方法的形式定义的,对象的属性是以成员变量的形式定义的,而类包括对象的属性和方法。

1.3 面对对象的特点

1.封装

封装是面对对象编程的核心思想,将对象的属性和行为封装起来,而将对象的属性和行为封装起来的载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想。

采用封装的思想保证了类内部数据结构的完整性,应用该类的用户不能轻易的直接操纵此数据结构,而只能执行类允许公开的数据。这样避免了外部对内部数据的影响,提高了程序的可维护性。

2.继承

继承性主要利用特定对象之间的共有属性,将共有属性定义为父类,特定属性定义为子类。继承关系可以使用属性关系来表示,父类与子类存在一种层次关系。一个类处于继承体系中,它既可以是其他类的父类,为其他类提供属性和行为,也可以是其他类的子类,继承父类的属性和方法。

3.多态

(1)将父类对象应用于子类的特征就是多态,多态性允许以统一的风格编写程序,以处理种类繁多的已存在的类以及相关类。该统一风格由父类实现,根据父类统一风格的处理,就可以实例化子类的对象。

(2)由于整个时间的处理都只依赖于父类的方法,所以日后只要维护和调整父类的方法即可,这样降低了维护ud难度,又节省了时间。

(3)在提到多态的同时,不得不提到抽象类和接口,因为多态的实现并不依赖具体类,而是依赖于抽象类和接口。

(4)抽象类不能实例化对象,在多态的机制中,父类通常会被定义为抽象类,在抽象类中给出一个方法的标准,而不给出实现的具体流程。

(5)在多态的机制中,比抽象类更加方便的方式是将抽象类定义为接口。由抽象方法组成的集合就是接口。

2.类

类是封装对象的属性和行为载体,对象的属性以成员变量的形式存在,对象的方法以成员方法的形式存在。

2.1 类的构造方法(构造器)

public book(){
    //构造方法体
}

public:构造方法修饰符。
book:本类的类名。

在类中定义构造方法时,需要定义无参构造器

构造方法中可以为成员变量赋值,这样实例化一个本类的对象时,相应的成员变量也将被初始化。

使用this关键字调用有参构造方法
public class Demo {
    public Demo(){
        this("this调用有参构造方法");
        System.out.print("无参构造方法");
    }
    public Demo(String name){
        System.out.print("有参构造函数");
    }
}

在无参构造方法中可以使用this关键字调用有参的构造方法。但使用这种方式值得注意的是:

只可以在无参构造方法中的第一句使用this关键字调用有参构造方法。

2.2 类的主方法

主方法是类的入口点,他定义了程序从何处开始;主方法提供对程序流向的控制,java编译器通过主方法来执行程序。

public static void main(String[] args){
        //方法体
}
主方法的特性

主方法是静态的。要直接在主方法中调用其他方法,则该方法必须也是静态的。

主方法没有返回值。

主方法的形参为数组。

用args[0]~args[n]分别代表程序的第一到第n个参数,可以使用args.length获取参数的个数。

public class Demo1 {

    public static void main(String[] args) {
        for(int i = 0;i<args.length;i++){
            System.out.println(args[i]);
        }
    }
}

2.3 成员变量

在java语言中对象的属性称为成员变量,也可以称为属性。

2.4 成员方法

在java语言中使用成员方法对应于类对象的行为。

权限修饰符  返回值类型  方法名(参数类型  参数名){
        ...//方法体
        return 返回值;
}

一个成员方法可以有参数,这个参数可以是对象也可以是基本数据类型的变量,同时成员方法有返回值和不返回值的选择,如果方法有返回值则在方法体中使用return关键字,如果没有则使用void关键字。

成员方法的返回值可以是计算结果,也可以是其他想要的数值、对象,返回值类型要与方法返回值类型相同。

在成员方法中可以调用其他成员方法和类成员变量,也可以在成员方法中定义一个变量,这个变量为局部变量。

如果一个方法中含有与成员变量同名的局部变量,则方法中对这个变量的访问以局部变量进行访问。

2.5 局部变量

局部变量是在方法被执行时创建,在方法执行结束时销毁。局部变量在使用时必须进行赋值操作或者初始化。

2.6 局部变量的有效范围

可以将局部变量的有效范围称为变量的作用域,局部变量的有效范围从该变量的声明开始到该变量的结束为止。

2.7 静态变量、常量和方法

由static修饰的变量、常量和方法被称为静态变量、常量和方法。

静态成员是属于类所有的,区别于个别对象,可以在本类或者其他类使用类名和“.”运算符调用静态成员。

类名.静态类成员

静态数据与静态方法的作用通常是为了提供共享数据方法,静态成员受public、private、protected修饰符的约束。

对静态语言的两点约束

在静态方法中不可以使用this关键字。

在静态方法中不可以直接调用非静态方法。

方法体中的局部变量不能声明为static。

小技巧

//如果在执行类时,希望先执行类的初始化动作,可以使用static定义一个静态区域。
public class example{
    static{
        //some
    }
}
//当这段代码被执行时,首先执行static块中的程序,并且只会执行一次。

2.8 权限修饰符

public:本类、本包其他类及子类、其他包的类或者子类可见
protected:本类、同包其他类或子类可见
private:本类可见
defailt:本类、本包其他类可见

2.9 this关键字

构造器互相调用,this放在构造器首行

public Test(){
    this (12);
}
public Test(int age){
    this ("adf");
    System.out.println("===>"+age);
}
public Test(String name){
    System.out.println("asss");
}
private void setName(String name){
    this.name = name;
}

this关键字被隐式的用于引用对象的成员变量和方法,this可以调用成员变量和成员方法。this引用就是对一个对象的引用。

public Book getBook(){
    return this;
    }

可以作为方法的返回值,将类的对象进行返回。

2.10 自定义图书类

建立Books类,定义三个成员变量分别表示书名、作者和价格,同时提供构造方法来修改成员变量。

public class Books {
    private String title;
    private double price;
    private String autor;
    public Books(String title,double price,String autor){
        this.autor = autor;
        this.price = price;
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public double getPrice() {
        return price;
    }

    public String getAutor() {
        return autor;
    }
}

建立测试类BookTest,创建book对象并输出其属性

public class BookTest {
public static void main(String[] args){
    Books book = new Books("阿弥陀佛么么哒",49.9,"那谁谁");
    System.out.println("书名:"+book.getTitle());
    }
}

3.对象

对象是由类抽象出来的,所有的问题都是通过对象来处理,对象可以操作类的属性和方法解决相关的问题。

3.1 对象的创建

对象是在一类事物中抽象出某一个特例,通过这个特例来处理这类事物出现的问题,在java语言中通过new操作符来创建对象。可以在java语言中使用new操作符调用构造方法创造对象。

Test test = new Test();
Test test = new Test("a");

Test:类名

test:创建Test类对象

new:创建对象操作符

“a”:构造方法的参数


test对象被创建出来时 ,test对象就是一个对象的引用,这个引用在内存中为对象分配了存储空间,可以在构造方法中初始化成员变量,当创建对象时,自动调用构造方法,也就是说在java语言中初始化与创建是被捆绑在一起的。

每个对象都是相互独立的,在内存中占据独立的内存地址,并且每个对象都具有自己的生命周期,当一个对象的生命周期结束时,对象变成了垃圾,由java虚拟机自带的垃圾回收机制处理,不能在被使用。

3.2 访问对象的属性和行为

当用户使用new操作符创建一个对象后,可以使用“对象.类成员”来获取对象的属性和行为。对象的属性和行为在类中是通过变量和成员方法的形式来表示的,所以当对象获取类成员,也就相应的获取了对象的属性和行为。
同一个类下,对象是相互独立的
用static关键字修饰作为全局变量使用

3.3 对象的引用

类名  对象引用名称

引用只是存放一个对象的内存地址,并非存放一个对象,严格说引用和对象是不同的,但是可以将这种区别忽略,如可以简单的说book是Book类的一个对象,而事实上应该说book是包含Book对象的一个引用。

3.4 对象的比较

两种对象的比较方法,分别为“==”运算符与equals()方法。

equals()方法是String类中的方法,它用于比较两个对象所指的内容是否相同。

“==”运算符比较的是两个对象的引用地址是否相等。

3.5 对象的销毁

每个对象都有生命周期,当对象的生命周期结束时,分配给该对象的内存地址将会被收回,在其他语言中需要手动收回废弃的对象,java语言拥有一套完整的垃圾回收机制,用户不必担心废弃的对象占用内存,垃圾回收器将回收无用的占用内存的资源。


何种对象会被java虚拟机视为垃圾

(1)对象引用超出其作用范围
(2)将对象赋值为null


垃圾回收器只能回收那些由new操作符创建的对象,如果某些对象不是通过new操作符在内存中获取的一块内存区域,这种对象可能不被垃圾回收机制所识别,所以在java语言中提供了一个finalize()方法,这个方法是Object类的方法,他被声明为protected,用户可以在自己的类中定义这个方法,如果用户在类中定义了finalize()方法,在垃圾回收时首先调用该方法,并且在下一次垃圾动作发生时,才能真正的回收对象占用的内存。


垃圾回收或是finalize()方法不保证一定发生,如java虚拟机面临内存耗损殆尽的情形,他是不会执行垃圾回收的。


垃圾回收不受人为控制,具体时间也是不确定的,所以finalize()方法也就无法执行,为此,java提供了System.gc()方法强制启动垃圾回收器。

3.6 统计图书销量

(1)在项目中创建Book类,在类中定义了一个静态的成员变量用于保存实例化的次数,在构造方法中实现技术器功能。

public class Book {
    private static int counter = 0;
    public Book(String title){
        System.out.println("售出此书:"+title);
        counter++;
    }
    public static int getCounter(){
        return counter;
    }
}

(2)创建Book类对象并输出创建对象的个数。

import java.util.Random;

public class Test1 {

    public static void main(String[] args) {
        String[] titles = {"a","b","c"};
        for(int i = 0;i<5;i++){
            new Book(titles[new Random().nextInt(3)]);
        }
        System.out.println("总计销售了"+Book.getCounter());
    }
}

3.7 计算对象哈希码

java语言中创建的对象是保存在堆中的,为了提高查找的速度而使用散列查找。散列查找的基本思想是定义一个键来映射对象所在的内存地址。当需要查找对象时,直接查找键就可以,这样就不用遍历整个堆来查找对象。


(1)在项目中创建Cat类,在类中定义4个成员变量分别表示猫咪的名字、年龄、重量、颜色,并提供构造方法来设置这些属性值。本类的重点内容在于重写equals()方法和hashCode()方法可以让相同的对象保存在相同的位置。

import java.awt.Color;

public class Cats {
    private String name;
    private int age;
    private double weight;
    private Color color;

    public Cats(String name,int age,double weight,Color color) {
        this.name = name;
        this.age = age;
        this.weight = weight;
        this.color = color;
    }
    @Override
    public boolean equals(Object obj){//重写Object类中的equals方法
        if(this == obj){
            return true;
        }
        if(obj == null){
            return false;
        }
        if(getClass()!=obj.getClass()){
            return false;
        }
        Cats cat =(Cats)obj;
        return name.equals(cat.name)&&(age==cat.age)&&
                (color==cat.color)&&(weight==cat.weight);
    }
    @Override
    public int hashCode(){  //重写Object类中的hashCode方法
        return 7*name.hashCode()+11*new Integer(age).hashCode()
                +13*new Double(weight).hashCode()+17*color.hashCode();
    }
}

(2)在main方法中建立三只猫咪,并为其初始化,然后输出猫咪的哈希码和比较结果。

import java.awt.Color;

public class Test2 {
    public static void main(String[] args) {
        Cats cat1 = new Cats("白白",12,21,Color.white);
        Cats cat2 = new Cats("兰兰",12,21,Color.blue);
        Cats cat3 = new Cats("白白",12,21,Color.WHITE);
        System.out.println("猫咪1号的哈希码:"+cat1.hashCode());
        System.out.println("猫咪2号的哈希码:"+cat2.hashCode());
        System.out.println("猫咪3号的哈希码:"+cat3.hashCode());
        System.out.println("猫咪1号是否与2号相同:"+cat1.equals(cat2));
        System.out.println("猫咪1号是否与3号相同:"+cat1.equals(cat3));
    }

}

4.经典范例


4.1 汉诺塔问题求解

汉诺塔问题描述如下:有A、B和C 3根柱子,在A上从下往上按照从大到小的顺序放着64个圆盘,以B为中介,把盘子全部移动到C上。移动过程中,要求任意盘子的下面要么没有盘子,要么只能有比他大的盘子。

public class HanoiTower {

    public static void moveDish(int level,char from,char inter,char to){
        if(level==1){
            System.out.println("从"+from+"移动盘子1号到"+to);
        }else{
            moveDish(level-1, from, to, inter);
            System.out.println("从"+from+"移动盘子"+level+"号到"+to);
            moveDish(level-1, inter, from, to);
        }
    }

    public static void main(String[] args) {
        int nDisks = 4;
        moveDish(nDisks,'A','B','C');
    }
}

4.2 单例模式的作用

(1)在项目中创建Emperor类,在类中将构造方法设置为私有,并提供了一个静态方法用于获得该类的实例。

public class Emperor {
    private static Emperor emperor = null;

    private Emperor() {  //减少错误是使用,避免程序混乱
    }
    public static Emperor getInstance(){
        if(emperor == null){
            emperor = new Emperor();
        }
        return emperor;
    }
    public void getName(){
        System.out.println("我是皇帝:Yking");
    }
}

(2)在类中创建三个皇帝对象,并进行输出。

public class Test {

    public static void main(String[] args) {
        System.out.println("创建皇帝对象1:");
        Emperor emperor1 = Emperor.getInstance();
        emperor1.getName();
        System.out.println("创建皇帝对象2:");
        Emperor emperor2 = Emperor.getInstance();
        emperor2.getName();
        System.out.println("创建皇帝对象3:");
        Emperor emperor3 = Emperor.getInstance();
        emperor3.getName();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值