面对象的向概念
面向对象是一种符合人类思维习惯的编程思想。现实生活中存在各种形态不同的事物,这些事物之间存在着各种各样的联系。在程序中使用对象来映射现实中的事物,使用对象的关系来描述事物之间的联系,这种思想就是面向对象。
提到面向对象,自然会想到面向过程,面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一一实现,使用的时候依次调用就可以了。面向对象则是把构成问题的事务按照一定规则划分为多个独立的对象然后通过调用对象的方法来解决问题。当然,一个应用程序会包含多个对象,通过多个对象的相互配合来实现应用程序的功能,这样当应用程序功能发生变动时,只需要修改个别的对象就可以了,从而使代码更容易得到维护。面向对象的特点主要可以概括为封装性、继承性和多态性,接下来针对这三种特性进行简单介绍
1.封装性
封装是面向对象的核心思想,将对象的属性和行为封装起来,不需要让外界知道具体实现细节,这就是封装思想。例如,用户使用电脑,只需要使用手指敲键盘就可以了,无需知道电脑内部是如何工作的,即使用户可能碰巧知道电脑的工作原理,但在使用时,并不完全依赖电脑工作原理这些细节。
2、继承性
继承性主要描述的是类与类之间的关系,通过继承,可以在无需重新编写原有类的情况下,对原有类的功能进行扩展。例如,有一个汽车的类,该类中描述了汽车的普通特性和功能,而轿车的类中不仅应该包含汽车的特性和功能,还应该增加轿车特有的功能,这时,可以让轿车类继承汽车类在轿车类中单独添加轿车特性的方法就可以了。继承不仅增强了代码的复用性、提高开发效率,还为程序的维护补充提供了便利。
3、多态性
多态性指的是在程序中允许出现重名现象,它指在一个类中定义的属性和方法被其它类继承后,它们可以具有不同的数据类型或表现出不同的行为,这使得同一个属性和方法在不同的类中具有不同的语义。例如,当听到“cut”这个单词时,理发师的行为是剪发,演员的行为表现是停止表演,不同的对象,所表现的行为是不一样的。
面向对象的思想光靠上面的介绍是无法真正理解的,只有通过大量的实践去学习和理解,才能将面向对象真正领悟。接下来的第三章、第四章将围绕着面向对象的三个特征(封装、继承、多态)来讲解Java这门编程语言
类与对象
面向对象的编程思想,力图让程序中对事物的描述与该事物在现实中的形态保持一致。为了做到这一点,面向对象的思想中提出了两个概念,即类和对象。其中,类是对某一类事物的抽象描述,而对象用于表示现实中该类事物的个体。
在面向对象的思想中最核心的就是对象,为了在程序中创建对象首先需要定义一个类。类是对象的抽象,它用于描述一组对象的共同特征和行为。类中可以定义成员变量和成员方法,其中成员变量用于描述对象的特征,也被称作属性,成员方法用于描述对象的行为,可简称为方法
案例:
package cn.itcase.chapter03.example01;
/*
* 描述人事务
* 都是人的共性内容
*/
public class person {
int age;//定义int类型变量age
//定义speak()方法
public void speak() {
System.out.println("大家好,我今年"+age+"岁")
}
}
在Java中,定义在类中的变量被称为成员变量,定义在方法中的变量被称为局部变量。如果在某一个方法中定义的局部变量与成员变量同名,这种情况是允许的,此时方法中通过变量名访问到的是局部变量,而并非成员变量,请阅读下面的示例代码:
class Person {
int age = 10;//类中定义的变量被称作成员变量
void speak() {
int age = 60;// 方法内部定义的变量被称作局部变量
System.out.println("大家好,我今年”+ age +"岁!");
}
}
上面的代码中,在Person类的speak()方法中有一条打印语句,访问了变量age;此时访问的是局部变量age,也就是说当有另外一个程序来调用speak()方法时输出的值为60,而不是10。
对象的创建与使用
应用程序想要完成具体的功能,仅有类是远远不够的,还需要根据类创建实例对象在Java程序中可以使用new关键字来创建对象,具体格式如下:
类名 对象名称 = new 类名();+例如,创建Person类的实例对象代码如下:
Person p = new Person () :+上面的代码中,“newPerson()”用于创建Person类的个实例对象,“Personp”则是声明了一个Person类型的变量p。中间的等号用于将Person对象在内存中的地址赋值给变量p,这样变量p便持有了对象的引用。
package cn.itcast.chaspter03.example01;
/*
*创建对象,访问对象中的成员
*/
public class Example01{
public static void main (String[]args){
Person p1 =new Person();//创建第一个Person类对象
Person p2=new Person();。。创建第二个Person类对象
p1.speak();//调用对象的方法
p2.speak();
package cn.itcase.chapter03.example01;
/*
* 描述人事务
* 都是人的共性内容
*/
public class person {
int age;//定义int类型变量age
//定义speak()方法
public void speak() {
System.out.println("大家好,我今年"+age+"岁")
}
}
在实例化对象时,Java虚拟机会自动为成员变量进行初始化,针对不同类型的成员变量,Java虚拟机会赋予不同的初始值,如下表所示。
成员变量类型 | 初始值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0F |
double | 0.0D |
char | 空字符,"\u0000" |
boolean | false |
引用数据类型 | null |
当对象被实例化后,在程序中可以通过对象的引用变量来访问该对象的成员。需要注意的时,当没有任何变量引用这个对象时,它将称为垃圾对象不能被使用。
类的设计
在Java中,对象是通过类创建出来的。因此,在程序设计时,最重要的就是类的设计。[接下来就通过一个具体的案例来学习如何设计一个类假设要在程序中描述一个学校所有学生的信息,可以先设计一个学生类(student),在这个类中定义两个属性name、age分别表示学生的姓名和年龄定义一个方法introduce()表示学生做自我介绍。根据上面的描述设计出来的Student类如下所示。
public class Student{
String name;//定义一个姓名属性
int age;//定义一个年龄属性
public void introduce(){
//方法打印属性name和age的值
System.out.println("大家好,我叫"+name+",我今年"+age+"岁");
}
}
类的封装
在设计一个类时,应该对成员变量的访问作出一些限定,不允许外界随意访问这就需要实现类的封装。
所谓类的封装是指在定义一个类时,将类中的属性私有化,即使用private关键字来修饰,私有属性只能在它所在类中被访问,如果外界想要访问私有属性,需要提供一些使用public修饰的公有方法,其中包括用于获取属性值的getXxx方法和设置属性值的setXxx方法。
package cn.itcase.chapter03.example04;
class Student {
private String name;//将name属性私有化
private int age;//将age属性私有化
//下面的公有的方法间接访问类中属性getxx方法,setxxx方法
public String getName (){
return name;
}
public void setName(String stuName){
name=stuName;
}
public int getAge(){
return age;
}
public void setAge(int stuAge){
age=stuAge;
}
public void introduce(){
System.out.println("大家好,我叫"+name+",我今年"+age+"岁");
}
}
public class Example04{
public static void main(String[]args){
Student stu=new Student();
stu.setAge(30);
stu.setName("韩强");
stu.introduce();
}
}
运行结果:
![](https://i-blog.csdnimg.cn/blog_migrate/318972ee9e2ecb8a859eba4aa017d6cc.png)
超市购物程序设计:
package cn.itcast.chapter03.task01;
/*
* 商品类
* 描述商品这个事物
*/
public class Product {
private String proName;//商品名
public String getProName() {
return proName;
}
public void setProName(String proName) {
this.proName=proName;
}
}
代码截图:
package cn.itcast.chapter03.task01;
/*
* 定义超市类
* 描述超市事物
* 超市名字
* 超市的仓库,存储商品
* 售货方法
*/
public class Market {
private String marketName;//超市名字
private Product[] productArr;
public String getMarketName() {
return marketName;
}
public void setMarketName(String marketName) {
this.marketName=marketName;
}
public Product[] getProductArr(){
return productArr;
}
public void setProductArr(Product[] productArr) {
this.productArr=productArr;
}
public Product sell(String name) {//卖货,指定商品名字
for(int i=0;i<productArr.length;i++) {//循环遍历仓库中每一个商品
if(productArr[i].getProName()==name) {//如果找到名字和要买的商品名字一样
return productArr[i];//返回该商品
}
}
return null;
}
}
代码截图:
package cn.itcast.chapter03.task01;
/*
* 描述人这个食物
* 人的名字
* 购物功能
*/
public class person {
private String name;//人名
public String getName() {
return name;
}
public void setName(String name) {
this.name=name;
}
public Product shopping(Market market,String name) {//购物,指定去哪个超市,商品名
return market.sell(name);//调用超市的卖货方法,指定商品名字,把卖出的货的结果返回
}
}
代码截图:
package cn.itcast.chapter03.task01;
public class Shopping {
public static void main(String[] args) {
//创建商品对象,给商品名字赋值
Product p1=new Product();
Product p2=new Product();
Product p3=new Product();
Product p4=new Product();
Product p5=new Product();
p1.setProName("电视机");
p2.setProName("洗衣机");
p3.setProName("豆浆机");
p4.setProName("空调机");
p5.setProName("吹风机");
//创建超市对象,给超市名字赋值,给仓库赋值
Market m=new Market();
m.setMarketName("家乐福");
m.setProductArr(new Product[]{p1,p2,p3,p4,p5});
//创建购物者
person p=new person();
p.setName("小韩");
//调用购物者的购物方法,指定超市和商品,得到结果
Product result=p.shopping(m,"电视机");
//根据结果进行判断
if(result!=null){
System.out.println(p.getName()+"在"+m.getMarketName()+"买到了"+result.getProName());
}else {
System.out.println(p.getName()+"白跑一趟,在"+m.getMarketName()+"什么也没买到");
}
}
}
代码及运行结果截图:
构造方法的定义
在一个类中定义的方法如果同时满足以下三个条件,该方法称为构造方法,具体如下:
1.方法名与类名相同
2.在方法名的前面没有返回值类型的声明
3.在方法中不能使用return返回一个值,但是可以单独写return语句来作为方法的结束
案例:
calss Person {
public person(){
System.out.println("无参的构造方法被调用了...");
}
}
public class Example05{
public static void main(String []args){
Person p=new Person();//实例化Person对象
}
}
构造方法的重载
与普通方法一样,构造方法也可以重载,在一个类中可以定义多个构造放啊,只要么欸个构造方法的参数类型或参数个数不用即可。在创建对象时,可以通过调用不同的属性进行赋值。
package Seven;
public class OverLoadTest {
public static int add(int a,int b) {//定义一个方法
return a+b;
}
public static double add(double a,double b) {//与第一个方法名相同、参数类型不同
return a+b;
}
public static int add(int a) {//与第一个方法参数个数不同
return a;
}
public static int add(int a,double b) {//先int参数,后double参数
return a;//输出int参数值
}
public static int add(double a,int b) {
return b;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("调用add(int,int)方法:"+add(1,2));
System.out.println("调用add(double,double)方法:"+add(2.1,3.3));
System.out.println("调用add(int)方法:"+add(1));
System.out.println("调用add(int,double)方法:"+add(5,8.0));
System.out.println("调用add(double,int)方法:"+add(5.0,8));
}
}
this关键字
this关键字
this关键字用于表示本类当前的对象,当前对象不是某个new出来的实体对象,而是当前正在编辑的类。this关键字只能在本类中使用。
例
public void setName(String name){//定义一个setName()方法
this.name=name;//将参数赋予类中的成员变量
}
在上述代码中看到,成员变量与setName()方法中的形式参数的名称相同,都为name。在Java语言中,规定使用this关键字来代表苯类对象的引用,this关键字被隐式地用于引用对象的成员变量和方法,如在上述代码中,this.name指的就是Book类中的成员变量,而this.name=name语句中的第二个name指的是形参name。实质上,setName()方法实现的功能就是将形参name的值赋予成员变量name。
this除了可以调用成员变量或成员方法,还可以作为方法的返回值。例如,返回图书类本类的对象,可以写成下面的形式:
public Book getBook(){
return this//返回Book类本类的对象
}
垃圾回收机制
在Java中,当一个对象成为垃圾后仍会占用内存空间,时间一长,就会导致内存空间的不足。针对这种情况,Java中引入了垃圾回收机制。有了这种机制,程序员不需要过多关心垃圾对象回收的问题,Java虚拟机会自动回收垃圾对象所占用的内存空间。
个对象在成为垃圾后会暂时地保留在内存中,当这样的垃圾堆积到一定程度时,ava虚拟机就会启动垃圾回收器将这些垃圾对象从内存中释放,从而使程序获得更多可用的内存空间。除了等待Java虚拟机进行自动垃圾回收外,还可以通过调用vstem.gc()方法来通知Java虚拟机立即进行垃圾回收。当一个对象在内存中被释放时,它的finalize()方法会被自动调用,因此可以在类中通过定义finalize()方法来观察对象何时被释放。
静态变量
在定义一个类时,只是在描述某类事物的特征和行为,并没有产生具体的数持只有通过new关键字创建该类的实例对象后,系统才会为每个对象分配空间存储各自的数据。有时候,开发人员会希望某些特定的数据在内存中只有一份而且能够被一个类的所有实例对象所共享。例如某个学校所有学生共享同一/学校名称,此时完全不必在每个学生对象所占用的内存空间中都定义一个变来表示学校名称,而可以在对象以外的空间定义一个表示学校名称的变量,所有对象来共享。
静态方法
在实际开发时,开发人员有时会希望在不创建对象的情况下就可以调用某个方法,换句话说也就是使该方法不必和对象绑在一起。要实现这样的效果,只需要在类中定义的方法前加上static关键字即可,通常称这种方法为静态方法。同静态变量一样,静态方法可以使用“类名.方法名”的方式来访问,也可以通过类的实例对象来访问。
注意:在一个静态方法中只能访问用static修饰的成员,原因在于没有被static修饰的成员需要先创建对象才能访问,而静态方法在被调用时可以不创建任何对象。
静态代码块
在Java类中,使用一对大括号包围起来的若干行代码被称为一个代码块,用static关键字修饰的代码块称为静态代码块。当类被加载时,静态代码块会执行由于类只加载一次,因此静态代码块只执行一次。在程序中,通常会使用静态代码块来对类的成员变量进行初始化。
成员内部类
在Java中,允许在一个类的内部定义类,这样的类称作内部类,这个内部类所在的类称作外部类。根据内部类的位置、修饰符和定义的方式可分为:成员内部类、静态内部类、方法内部类。本小节将针对成员内部类进行讲解。
在一个类中除了可以定义成员变量、成员方法,还可以定义类,这样的类被称作成员内部类。在成员内部类中,可以访问外部类的所有成员。如果想通过外部类去访问内部类,则需要通过外部类对象去创建内部类对象创建内部类对象的具体语法格式如下:
外部类名.内部类名 变量名=new 外部类名().内部类名();
任务3-2
package cn.itcast.chapter03.task02;
/*
* 定义银行类
* 属性:银行名称,储户名称,密码,余额,交易额度
* 功能:开门营业,存钱,取钱,关门
*/
public class Bank {
static String bankName;//定义静态变量银行名字
private String name;//储户名字
private String password;//密码
private double balance;//账户余额
private double turnover;
//静态方法,打出银行的欢迎语句
public static void welcome() {
System.out.println("欢迎来到"+bankName+"------------");
}
public Bank(String name,String password,double turnover) {
this.name=name;
this.password=password;
this.balance=turnover-10;
System.out.println(name+"开户成功,账户余额"+balance);
}
//存款功能
public void deposit(double turnover) {
balance=balance+turnover;
System.out.println(name+"你好,你的账户已经存入"+turnover+"元"+"当前余额"+balance+"元");
}
//取款功能
public void withdrawal(String password,double turnover) {
//根据传入的变量与成员变量对比,判断密码是否正确
if(this.password!=password) {
System.out.println("您输入的密码错误");
return;
}
//判断余额是否充足
if(balance-turnover>0) {
balance=balance-turnover;
System.out.println(name+"您好,您的账户已取出"+turnover+"元,当前余额"+balance+"元");
}else {
System.out.println("对不起,账户余额不足:");
}
}
//静态方法,打印出银行欢迎下次光临
static void wecomeNext() {
System.out.println("请携带好随身财物,欢迎下次光临"+bankName+"---------------");
}
}
package cn.itcast.chapter03.task02;
public class Trade {
public static void main(String[] args) {
//定义一家银行,给静态变量(银行名字)赋值,类名.调用成员变量
Bank.bankName="招商银行";
//银行的打印欢迎光临,调用静态方法
Bank.wecomeNext();
//开户操作通过调用构造方法进行开户
Bank bank=new Bank("小梦","654321",100);
//进行存款操作
bank.deposit(500);
//取款时密码输入错误,取款失败
bank.withdrawal("123456",200);
//取款时密码正确,余额充足,取款成功
bank.withdrawal("654321", 1000);
//取款时密码正确,余额充足,取款成功
bank.withdrawal("654321", 200);
//银行打印道别语句,调用静态方法
Bank.wecomeNext();
}
}
类的继承
Java中,类的继承是指在一个现有类的基础上去构建一个新的类构建出来的新类被称作子类,现有类被称作父类,子类会自动拥有父类所有可继承的属性和方法。在程序中,如果想声明一个类继承另一个类,需要使用extends关键字
class Child extends Parent{}
重写父类的方法
在继承关系中,子类会自动继承父类中定义的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类的方法进行重写。需雾注意的是在子类中重写的方法需要和父类被重写的方法具有相同的方法名、参数列表以及返回值类型。
super关键字
当子类重写父类的方法后,子类对象将无法访问父类被重写的方法,为了解决这个问题
,在Java中专门提供了一个super关键字用于访问父类的成员。例如访问父类的成员变量、成员方法和构造方法。接下来分为两种情况来学习super关键字的具体用法。
1.使用super关键字访问父类的成员变量。具体格式如下:
super.成员变量
super.成员方法({参数1,参数2……})
2.使用super关键字访问父类的构造方法。具体格式如下:
super.({参数1,参数2……})
final关键字
final关键字可用于修饰类、变量和方法,它有“无法改变”或者“最终的含义,因此被final修饰的类、变量和方法将具有以下特性:
final修饰的类不能被继承。
final修饰的方法不能被子类重写。
final修饰的变量(成员变量和局部变量) 是常量,只能赋值一次
Java中的类被final关键字修饰后,该类将不可以被继承,也就是不能够派生子类。
抽象类
当定义一个类时,常常需要定义一些方法来描述该类的行为特征,但有时这些方法的实现方式是无法确定的。例如前面在定义Animal类时,shout()方法用于表示动物的叫声,但是针对不同的动物,叫声也是不同的,因此在shout()方法中无法准确描述动物的叫声。
针对上面描述的情况,Java允许在定义方法时不写方法体,不包含方法体的方法为抽象方法,抽象方法必须使用abstract关键字来修饰,具体示例如下:
abstract void shout();//定义抽象方法shout()
接口
如果一个抽象类中的所有方法都是抽象的,则可以将这个类用另外一种方式来定义,即接口。接口是由常量和抽象方法组成的特殊类,是对抽象类的进一步抽象。
在定义接口时,需要使用interface关键字来声明,其语法格式如下:
[public] interface 接口名[extends 接口1,接口2……]{
[public][static][final]数据类型 常量名=常量值;
[public][abstract]返回值 抽象方法名(参数列表);
}
为了加深初学者对接口的认识,接下来对接口的特点进行归纳,具体如下:
接口中的方法都是抽象的,不能实例化对象.
接口中的属性只能是常量。
当一个类实现接口时,如果这个类是抽象类,则实现接口中的部分方法即可,否则需要实现接口中的所有方法。
一个类通过implements关键字实现接口时,可以实现多个接口,被实现的多个接口之间要用逗号隔开。具体示例如下:
interface Running{
程序代码……
}
interface Flying{
程序代码……
}
Interface Eating extends Runing,Flying{
程序代码……
}
任务4-1USB接口程序设计
package cn.itcast.chapter04.task01;
/*
* 定义一个名为USB的接口
*/
public interface USB {
public void turnOn();//启动
public void turnOff();//关闭
}
package cn.itcast.chapter04.task01;
/*
* 电脑类
* 有很多USB插槽
* 连接USB设备功能
* 开机功能,关闭功能
*/
public class Computer {
private USB[]usbArr=new USB[4];
//向电脑上连接USB设备
public void add(USB usb) {
//遍历数组,获取所有的插槽
for(int i=0;i<usbArr.length;i++) {
if(usbArr[i]==null) {
//将设备链接在USB插槽上
//将USB接口实现类对象,存储到了USB的数组中
usbArr[i]=usb;
break;
}
}
}
//电脑的开机功能
public void poveOn() {
//循环遍历所有插槽
for(int i=0;i<usbArr.length;i++) {
//如果发现数组中存储了USB接口实现类对象
if(usbArr[i]!=null) {
//调用设备上的开启功能
usbArr[i].turnOn();
}
}
System.out.println("电脑开机成功");
}
//电脑关机功能
public void poweroff() {
for(int i=0;i<usbArr.length;i++) {
if(usbArr[i]!=null) {
usbArr[i].turnOff();
}
}
System.out.println("电脑关机成功!");
}
}
package cn.itcast.chapter04.task01;
/*
* 键盘
*/
public class KeyBoard implements USB {
public void turnOn() {
System.out.println("键盘启动了!");
}
public void turnOff() {
System.out.println("键盘关闭了!");
}
}
package cn.itcast.chapter04.task01;
public class Mouse implements USB {
@Override
public void turnOn() {
System.out.println("鼠标启动了!");
}
@Override
public void turnOff() {
System.out.println("鼠标关闭了!");
}
}
package cn.itcast.chapter04.task01;
public class Mic implements USB {
@Override
public void turnOn() {
System.out.println("麦克风开启了");
}
@Override
public void turnOff() {
System.out.println("麦克风关闭了");
}
}
package cn.itcast.chapter04.task01;
public class Test01Test {
public static void main(String[] args) {
//创建电脑类对象
Computer c=new Computer();
//向电脑中添加USB设备,鼠标,麦克风和键盘设备
c.add(new Mouse());
c.add(new Mic());
c.add(new KeyBoard());
c.poveOn();//调用电脑的启动方法
System.out.println();
c.poweroff();//调用电脑的关机方法
}
}
67:
多态
多态的概念
在设计一个方法时,通常希望该方法具备一定的通用性。例如要实现一个动物叫的方法,由于每种动物的叫声是不同的,因此可以在方法中接收一个动物类型的参数,当传入猫类对象时就发出猫类的叫声,传入犬类对象时就发出犬类的叫声。在同一个方法中,这种由于参数类型不同而导致执行效果各异的现象就是多态。继承是多态得以实现的基础。在Java中为了实现多态,允许使用一个父类类型的变量来引用一个子类类型的对象,根据被引用子类对象特征的不同,得到不同的运行结果。
在多态的学习中,涉及到将子类对象当作父类类型使用的情况,此种情况在Java的语言环境中称之为“向上转型”,例如下面两行代码
Ani-aian=newCc11://Ct对聚当作A1类型来使用
AnImalAn2=new Dog1) //将Dcg对象当作A=s1类型来使用
将子类对象当作父类使用时不需要任何显式地声明,需要注意的是,此时不能通过父类变量去调用子类中的特有方法
69
Object类
在JDK中提供了一个object类,它是类层次结构的根类,每个类都直接或间接继承自该类,所有对象 (包括数组) 都实现了这个类的方法。obiect类中的常用方法如下表所示
匿名内部类
在编写Java程序时,在类里面定义的类称之为内部类(innerClass),内部类是外部类的一个成员。Java内部类可以分为:成员内部类、方法内部类和匿名内部类等。
在前面多态的讲解中,如果方法的参数被定义为一个接口类型,那么就需要定义一个类来实现接口,并根据该类进行对象实例化。除此之外,还可以使用匿名内部类来实现接口。所谓匿名内部类就是没有名字的内部类,表面上看起来它似乎有名字,实际那不是它的名字。当程序中使用匿名内部类时,在定义匿名内部类的地方往往直接创建该类的一个对象。