类和对象(第六章)

一、对象
在现实生活中,随处可见的一种事物就是对象。对象是事物存在的实体,如人、书桌、计算机、高楼大厦等。人类解决问题的方式总是将复杂的事物简单化,于是就会思考这些对象都是由哪些部分组成的。通常都会将对象划分为两个部分,级静态部分和动态部分。顾名思义,静态部分就是不能动的部分,这个部分被称为“属性”,任何对象都会具备其自身属性,如一个人,其属性包括高矮、胖瘦、性别、年龄等。动态部分即对象可执行的动作,被部分被称为“行人”,也是一个值得探讨的部分,同样对于一个人,其可以哭泣、微笑、说话、行走、这些都是人具备的行为。人类通过探讨对象的属性和观察对象的行为来了解对象。

在计算机的世界中,面对对象程序设计的思想要以对象来思考问题,首先要将现实世界的实体抽象为对象,然后考虑这个对象具备的属性和行为。例如,现在面临一只大雁要从北方飞往南方这样一个实际问题,试着以面向对象的思想来解决这一实际问题

(1)从这一问题中抽象出对象,这里抽象出的对象为大雁

(2)识别这个对象的属性。对象具备的属性都是静态属性,如大雁有一对翅膀、黑色的羽毛等。(3)识别这个对象的动态行为,即这只大雁可以进行的动作,如飞行、觅食等,这些行为都是这个对象基于其竖向而具有的动作,

(4)识别这个对象的属性和行为后,这个对象被定义完成了。然后,可以根据这只大雁具有的特征制定这只大雁从北方到南方的具体方案,以解决这个问题

二、类
不能将一个事物描述成一类事物,如一只鸟不能称为一只鸟类。但如果要给某一类事物一个统称,就需要用到类这个概念。

类就是同一类事物的统称,如果将将现实世界中的一个事物抽成对象,类就是这类对象的统称,如鸟类、家禽类、人类等。类是构造对象时所依赖的规范,如一只鸟有一对翅膀,它可以用这对翅膀飞行,而基本上所有的鸟类都具有“翅膀”,这个特性和飞行的技能,这样具有相同的特性和行为的一类事物就称为类,类的思想就是这样产生的。更为恰当的描述为,类是世间事物的抽象称呼,而对象则是这个事物对应的的实体。如果要面临实际问题,通常需要实例化类对象来解决。例如,鸟类封装了所有鸟的共同属性和应具有的行为。

三、封装
面向对象程序设计具有一下特点:封装性、继承性和多态性。

封装是面对对象编程的核心思想。将对象的属性和行为封装起来,其载体就是类,类通常对客户隐藏其实现细节,这就是封装的思想。例如,用户使用计算机时,只需要用手指敲击键盘就可以实现一些功能,无须依赖计算机内部是如何工作的。即使知道计算机的工作原理,在使用计算机时也并不完全依赖于与计算机工作原理等细节。

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

四、继承
类与类之间同样具有关系,这种关系被称为关联。关联主要描述两个类之间的一般二元关系,例如,一个百货公司类与销售员类就是一个关联,学生类与教室类也是一个关联。两个类之间的关系有很多种,继承是冠梁的一种。

当处理一个问题时,可以将一些有用的类保留下来,在遇到问题时拿来复用。假如这时需要信鸽送信的问题,我们很自然就会想到之前所描述的类。由于鸽子是奈鸟类,具有与鸟类相同的属性和行为,便可以在创建信鸽类时将鸟类拿来复用,并且保留鸟类具有的属性和行为,不过,并不是所有的鸟类都有送信的习惯,因此还需要再添加一些信鸽具有的独特属性级行为,鸽子类保留了鸟类的属性和行为,这样就节省了定义鸟和鸽子共同具有的属性及行为的时间,这就是继承的基本思想;继承性主要利用特定对象之间的共有属性。

五、多态
在第四节中介绍了继承、父类和子类,其实将父类对象用于子类的特征就是多态。依然以图类来说明多态类来说明多态,每个图形都拥有绘制自己的能力,这个能力可以看作是该类具有的行为,如果将子头
的对象统一看作是父类的实例对象,这样当绘制图形时,简单地调用父类也就是图形类绘制图形的方法,即可绘制任何图形,这就是多态最基本的思想。

多态性允许以统一的风格编写程序,以处理种类繁多的已存在的类及相关类。该统一风格可以由
父类来实现,根据父类统一凤格的处理,可以实例化子类的对象。由于整个事件的处理都只依赖于父
类的方法,所以日后只要维护和调整父类的方法即可,这样就降低了维护的难度,节省了时间。
提到多态,就不得不提抽象类和接口,因为多态的实现并不依赖于具体类,而是依赖于抽象类和
接口
再回到绘制图形的实例上来。图形类作为所有图形的父类,具有绘制图形的能力,这个方法可以
称为“绘制图形”,但如果要执行这个“绘制图形”的命令,没有人知道应该画什么样的图形,并且如
果要在图形类中抽象出一个图形对象,没有人能说清这个图形究竟是什么图形,所以使用“抽象”这
个词来描述图形类比较怡当。在Java 语言中,称这样的类为抽象类,抽象类不能实例化对象。在多态
的机制中,父类通常会被定义为抽象类,在抽象类中给出一个方法的标准,而不给出实现的具体流程。
实质上这个方法也是抽象的,如图形类中的“绘制图形”方法只提供一个可以绘制图形的标准,并没
有提供具体绘制图形的流程,因为没有人知道究竞需要绘制什么形状的图形。
在多态的机制中,比抽象类更方便的方式是将抽象类定义为接口。由抽象方法组成的集合就是接
口。接口的概念在现实中也极为常见,如从不同的五金商店买来螺丝帽和螺丝钉,螺丝帽很轻松地就
可以拧在螺丝钉上,可能螺丝帽和螺丝钉的厂家不同,但这两个物品可以轻易地组合在一起,这是因
为生产螺丝帽和螺丝钉的厂家都遵循着统一的标准,这个统一的标准在 Java 中就是接口。依然拿“绘
制图形〞来说明,可以将“绘制图形”作为一个接口的抽象方法,然后使图形类实现这个接口,同时
实现 “绘制图形” 这个抽象方法,当三角形类需要绘制时,就可以继承图形类,重写其中的“绘制图
形〞方法,并改写这个方法为 “绘制三角形”,这样就可以通过这个标准绘制不同的图形。

1.2 类
1.1.1成员变量
在lava 中,对象的属性也称为成员变量,成员变量可以是任意类型,整个类中均是成员变量什
范围。下面通过一个实例来演示成员变量在类中所处的位置。
创建一个 Book 类,在类中设置一个name 属性,并为该属性编写 Getter/ Setter 方法

public chass book{//类
    private String name;//String类型的成员变量
    public String getName(){//name的getter方法
        return name;
    }
    public void setName(String name){//name的setter方法
        this.name = name;//将参数赋予类总的成员变量
    }
 
}

在上面这个实例中可以看到,在Java 语言中需要使用 class 关键字来定义类,Book 是类的名称。
同时在Book 类中定义了一个成员变量,成员变量的类型为 String 类型。其实成员变量就是普通的交量,
可以为它设置初始值,也可以不设置初始值。如果不设置初始值,则会有默认值。读者应该注意到成
员变量 name 前面有一个 private 关键字,它用来定义一个私有成员。

1.1.2 成员方法
在Java语言中,使用成员方法对应于类对象的行为。以book类为例,它包含getName()和setName()两个方法,这两个成员方法分别为获取图书名称和设置图书名称的方法

定义成员方法的语法格式如下

-一个个成员方法可以有参数,这个参数可以是对象,也可以是基本数据类型的变量,同时成员方法

有返回值和不返回任何值的选择,如果方法需要返回值,可以在方法体中使用 retur 关键字,使用这个关键字后,方法的执行将被终止。

注意:要使Java代码中的成员方法无返回值,可以使用void关键字表示。

成员方法的返回值可以是计算结果,也可以是其他想要的数值和对象,返回值类型要与方法返回
的值类型一致。
在成员方法中可以调用其他成员方法和类成员变量,如在例 6.1的geIName()方法中就调用了
setName()方法将图书名称赋子一个值。同时,在成员方法中可以定义一个变量,这个变量为局部变量。

说明:如果一个方法中含有成员变量同名的局部变量,则方法中对这个变量的访问以局部变量进行类的成员变量和成员方法也可以统称为类成员。

1.2.3 权限修饰符
Java中的权限修饰符主要包括private、public、和Protected这些修饰符控制着对类和类的成员变量以及成员方法的访问。如果一个类的成员变量或成员方法被修饰为 private,则该成员变量只能在本类
中被使用,在子类中是不可见的,并且对其他包的类也是不可见的。如果将类的成员变量和成员方法
的访问权限设置为 publie,那么除了可以在本类使用这些数据,还可以在子类和其他包的类中使用。如
果一个类的访问权限被设置为 private,这个类将隐藏其内的所有数据,以免用户直接访问它。如果需
要使类中的数据被子类或其他包中的类使用,可以将这个类设置为 public 访问权限。如果
一个类使用
protected 修饰符,那么只有本包内的该类的子类或其他类可以访问此类中的成员变量和成员方法。
这么看来,public 和protected 修饰的类可以由子类访问,如果子类和父类不在同一包中,那么只
有修饰符为public 的类可以被子类进行访问。如果父类不允许通过继承产生的子类访问它的成员变量,
那么必须使用 private 声明父类的这个成员变量。表6.1 中描述了private、protected 和 public 修饰符的修饰权限。

 

在上述代码中,由于类的修饰符为默认修饰符,即只有一个包内的其他类和子类可以对该类进行
访问,而 AnyClass 类中的 doString()方法却又被设置为 public 访问权限,即使这样,doString()方法的
访问权限依然与 AnyClass 类的访问权限相同。
在 ChangeDemo 类中创建静态的 exchange0方法,该方法可以将数组参数 art 的前两个元素值互换

通过在方法中定义一个保存临时数据的局部变量 tmp,利用tmp 交换两个元素的值。

 

public class ChangDemo {
	public static int[] exchange(int[]arr) {
		int tmp = arr[0];//创建局部变量tmp,保存数组第一个元素的值
		arr[0] = arr[1];//第二个元素值赋给第一个元素
		arr[1] =tmp;//第二个元素值改为tmp
		return arr;
	}
	public static void main(String[] args) {
		int arr[] = {17,29};
		System.out.println("第一个值="+arr[0]+",第二个值="+arr[1]);
		arr =exchange(arr);
		System.out.println("第一个值="+arr[0]+",第二个值="+arr[0]);
	}
 
}

运行结果如下:

1.2.4 类的构造方法

产生对象但信息不全面(需要传入参数)

 

	
	//构造方法:调用构造方法创造一个对象
	public Bird(String name,String wing,String mouth,String head) {  //传入参数//构造了鸟这个类
		this.name = name;
		this.wing = wing;
		this.mouth = mouth;
		this. Head = head;
		
	}

构造方法的特点如下:

1.构造方法没有返回值

2.构造方法的名称要与本类的名称相同

 构造方法的定义语法格式如下:

 
  1.  
    public Book(){
    ...      //构造方法体
    }

    public:构造方法修饰符

    Book:构造方法的名称

    例题

    public class EggCake {
     int eggCount;   //鸡蛋灌饼里蛋的个数
     
     public EggCake(int eggCount) {   //参数为鸡蛋灌饼里蛋的个数的构造方法
      this.eggCount=eggCount;   //将参数eggCount的值赋给属性eggCount
      
     }
     public EggCake() {   //无参数构造方法,默认给饼加一个蛋
      //调用参数为鸡蛋灌饼里蛋的个数的构造方法,并设置鸡蛋灌饼里蛋的个数为1
      this(1);
      
     }
     public static void main(String[]args) {
      EggCake cake1=new EggCake();
      System.out.println("顾客不要求加蛋的数量,饼里会有"+cake1.eggCount+"个蛋。");
      EggCake cake2=new EggCake(2);
      System.out.println("顾客要求加2个蛋,饼里会有"+cake2.eggCount+"个蛋。");
     }
     
    }
    运行结果如下:

 注意:虽然静态成员也可以使用 ‘对象、静态成员”的形式进行调用,但通常不建议用这样的形式,因为这样容易混淆静态成员和非静态成员。
静态变量与静态方法的作用通常是为了提供共享数据或方法,如数学计算公式等。尽管使用这种
方式调用静态成员比较方便,但静态成员同样遵循着public、private和protected修饰符的约束。
 

例题6.5

public class Cust {//顾客类
	static int count = 0;//共享的属性:人数
	String name;//名称属性
	public Cust(String name) {
		this.name = name;//记录名称
		count++;//人数递增
	}
	
	public static void main(String[] args) {
		Cust c1 = new Cust ("tom");
		System.out.println("我是第"+Cust.count+"名顾客,我叫"+c1.name);
		Cust c2 = new Cust ("张三");
		System.out.println("我是第"+Cust.count+"名顾客,我叫"+c2.name);
		Cust c3 = new Cust ("我是狗蛋");
		System.out.println("我是第"+Cust.count+"名顾客,我叫"+c3.name);
	}
 
}

 运行结果如下:

 如果在执行类时,希望先执行类的初始化动作,可以使用static定义一个静态区域,这块区域放
为静态代码块。当类文件被执行时,会首先执行static块中的程序,并且只会执行一次。静态代码块的
语法如下:

 

public class example{
    static{
        ...  //可以在这里写初始化的代码
    }
}

最后总结以下使用static关键字要注意的几点:
在静态方法中不可以使用this关键字。
在静态方法中不可以直接调用非静态方法。
局部变量不可以使用static关键字声明。
主方法必须用static声明。
只有内部类可以使用static关键字声明。

 

1.2.5类的主方法

主方法的语法如下:

public static void main(String[] args){
    ...   //方法体
}

在主方法的定义中可以看到其具有以下特性:
主方法是静态的,所以如要直接在主方法中调用其他方法,则该方法必须也是静态的。
主方法没有返回值。
主方法的形参为数且。其中,args[0]~args[n]分別代表程序的第一个参数到第n个参数,可以使用arga.length获取参数的个数。

例题6.6

package duilian;
 
public class maindemo {
 
	public static void main(String[] args) {//主方法
		// TODO Auto-generated method stub
		for(int i=0;i<args.length;i++) {//根据参数个数做循环操作
			System.out.println(args[i]);//循环打印参数内容
			
		}
	}
 
}

运行结果如下: 

 

运行代码前,需要先设置运行的参数,步骤:

(1)在Eclipse 中的 MainDemn java 文件上单击鼠标右键,在弹出的快捷菜单中选择 “运行方式”1
运行代码前,先要在 Eclipse 中设置运行参数,步骤如下:

(2)在“运行配置”对话框中选择“自变量”
“运行配置”(英文版为 Run As / Run Configrations),弹出
Arguments)选项卡,在“项目” (Program arguments),(Run Configrations)对话框。
运行配置文本框中输入相应的参数,每个参数问按 Enter 键隔开。具体设置如图 6.11 所示。

(3)单击“运行”按钮,查看控制合运行结果,结果如下:

 

1.2.6对象

使用new操作符调用构造方法创建对象,语法如下:​​​​​​​

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

例题6.7

package duilian;
 
public class people {
		String name;//名字
		int age;//年龄
		String sex;
		
		public people() {//构造方法
		}
		
		public people(String name,int age,String sex) {
			this.name=name;//记录名称
			this.age=age;
			this.sex=sex;
		}
		
		public static void main(String[] args) {
			// TODO Auto-generated method stub
			people p1=new people("tom",23,"男");
			people p2=new people("liy",19,"女");		
			
	}
 
}

1.2.7访问对象的属性和行为

package duilian;
public class dog {
		String name;//名字
		String color;//颜色
		String vioce;//声音
		
		
		public dog(String name,String color,String vioce) {
			this.name=name;
			this.color=color;
			this.vioce=vioce;
		}
		
		public void call() {//叫
			System.out.println(vioce);
		}
		
		
		
		public static void main(String[] args) {
			// TODO Auto-generated method stub
		dog d1=new dog("毛毛","白色","汪汪汪");
		System.out.println(d1.name+"的颜色是"+d1.color);//对象属性
		System.out.println(",叫起来的声音:");
		d1.call();//对象行为
		
		dog d2=new dog("灰灰","灰色","嗷呜");
		System.out.println(d2.name+"的颜色是"+d2.color);
		System.out.println(",叫起来的声音:");
		d2.call();
	}
 
}

1.2.7访问对象的属性和行为

1.2.8 对象的引用
类名 对象的引用变量

1.2.9 对象的销毁
每个对象都有生命周期,当对象的生命周期结束时,分配给该对象的内存地址需要被回收

何种对象会被Java虚拟机视为“垃圾”。主要包括以下两种情况:

对象引用超过其作用范围,这个对象将被视为垃圾。

虽然Java的垃圾回收机制已经很完善,但垃圾回收器只能回收那些由new操作符创建的对象。某些对象不是通过new操作符在内存中获取存储空间的,这种对象无法被垃圾回收机制所识别。在Java中,提供了一个finalize(方法,这个方法是Object类的方法,它被声明为protected,用户可以在自己的类中定义这个方法。如果用户在类中定义了finalize)方法,在垃圾回收时会首先调用该方法,在下一次垃圾回收动作发生时,才真正回收被对象占用的内存。
      说明:需要明确的是,垃圾回收或finalize()方法并不保证一定会发生。如果Java虚拟机内存损耗待尽,它将不会执行垃圾回收处理。
      由于垃圾回收不受人为控制,具体执行时间也不确定,所以finalize()方法也就无法执行。为此,Java提供了System.gc0方法来强制启动垃圾回收器,这与给120打电话通知医院来救护病人的道理一样,主动告知垃圾回收器来进行清理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值