JAVA基础--面向对象


前言

面向对象的三大特征:封装、继承、多态


一、类和对象

1、软件开发方式

面向过程

一种较早的编程思想,强调的是该怎么去做–即功能的
执行过程,先干什么,后干什么。

面向过程思想中的函数(类似于方法)是一等公民,每个函数负责完成某一个功能,用以接受输入数据,函数对输入数据进行处理,然后输出结果数据。

而每一个功能我们都使用函数(类似于方法)把这些步骤一步一步实现,使用的时候依次调用函数就可以了。
在这里插入图片描述
因而,面向过程的设计思想,系统软件适应性差,可拓展性差,维护性低。

面向对象

一种基于面向过程的新的编程思想,顾名思义该思想是站在对象的角度思考问题,把多个功能合理的放到不同对象里,强调的是该让谁来做

面向对象最小的程序单元是类,必须先存在类的定义再有对象,而具备某种功能的实体,称为对象。

面向对象描述

举个简单的例子
在这里插入图片描述

面向过程和面向对象各有千秋,面向对象更符合我们常规的思维方式,稳定性好,可重用性强,易于开发大型软件产品,有良好的可维护性,它拥有三大特征:
封装(Encapsulation)
继承(Inheritance)
多态(Polymorphism)

2、成员变量和局部变量

成员变量:又称之为字段(Field)。直接定义在类中,方法外面。
局部变量:除了成员变量,其他都是局部变量,具体存在于三个地方
· 方法内
· 方法的形参
· 代码块中(一对花括号)

在这里插入图片描述
变量根据定义的位置不同,也决定了各自的作用域是不同的,关键看变量所在的那对花括号{ }

局部变量:从开始定义的位置开始,只能在自己所在的花括号内有效
成员变量:在所定义的类中都有效

{ } 也常常被称为作用域,作用域可以嵌套,内层作用域可以访问外层作用域的变量,反之不成立。

变量的初始化表示在内存中开辟存储空间,只有初始化之后,才能使用。

局部变量:没有初始值,所以必须先声明后赋值再使用
成员变量:默认是有初始值的,不同类型的初始值,如下图:
在这里插入图片描述
变量的生命周期,表示变量在内存在能存活多久。
成员变量:存储在堆内存中,随着对象的销毁而销毁
局部变量:存储在栈内存中,随着所定义方法的调用结束而销毁

局部变量存储在方法中,每次调用方法都会在栈空间开辟一块内存空间——栈帧,方法调用结
束,栈帧就被销毁了,内存中的存储的变量数据也销毁了。

##3. 类(重点)
类是拥有相同特征(状态)和相同行为(功能)的多个事物的抽象(抽出像的部分)描述。
在程序中,类就可以作为一种新型的数据类型。可以使用类来声明变量。

描述类或者说定义类,就从状态和行为上分析,那么怎么来表示状态和行为呢?
· 使用成员变量来表示特征(状态)
· 使用成员方法来表示行为(功能)

语法格式

public class 类名 { 
//可编写0到N个成员变量
	 [修饰符] 数据类型 变量名1;
	 [修饰符] 数据类型 变量名2; 
	 //可编写0到N个成员方法 
	 [修饰符] 返回值类型 方法名称(参数){
	  	//方法体 
	  } 
}

注意
· 成员变量和方法都 能使用static修饰,修饰符是可选用的,都先不使用任何修饰符
· 在面向对象设计中,描述对象的类和测试类分开来编写
· 在描述对象的类中,不需要定义main方法,专门在测试类中提供main方法。

对象操作(重点掌握)
对象 : 对象是类的一个具体实例,它用于描述一个具体的个体。
对象是独立的,唯一的个体。
对象一定属于某一类(型),具备该类的特性和行为。

创建对象

类名 对象变量名 = new 类名();

  1. 直接打印对象的时候,打印的是类似于数组一样的hashCode值(先不管,后面讲)

System.out.println(对象变量名);//格式如:类名@3294e4f4

  1. 匿名对象:创建对象之后没有赋给某一个变量,只能使用一次(先知道)

new 类名();

对象操作字段(成员变量)

  1. 给字段设置数据

对象变量名.字段名 = 值;

  1. 获取字段数据

数据类型 变量 = 对象变量名.字段名;

对象调用方法

对象变量名.方法(参数);

4.类和对象的关系

面向对象思想中有两个非常重要的概念,类和对象,其中:类(class),是对某一类事物的抽象描述(状态和行为)
对象(object),表示现实生活中该类事物的个体,也称之为实例。
类可以看作是对象的数据类型,就好比无论你是谁,只要是人,那么类型就是人。

5.构造器/构造方法(重点掌握)

构造器,也称之为构造方法(Constructor),作用是用来创建对象和给对象做初始化操作,专门用于构
造一个对象。

Student student = new Student();

这段代码,是在通过调用Student类的构造器,来创建对象。

// 普通方法 
[修饰符] 返回值 方法名(参数列表){
 }
 // 构造方法语法 
 [修饰符] 类名(参数列表){ }

1、构造器名称必须和类名相同
2、不能定义返回类型
3、构造器中不能使用return语句

默认的构造器

如果源文件中没有定义构造器,编译器在编译源文件的时候,会创建一个缺省的构造器。

默认构造器的特点:无参数、无方法体。

类是否使用public修饰(下面结论知道就行):
使用,则编译器创建的构造器也使用public修饰
不使用,则编译器创建的构造器也不使用public修饰

记住构造器的定义语法和功能,手动写出构造器代码,认识同一个类中的多个构造器之间是重载关系。

二、封装

1、封装思想

把对象的字段和方法存放在一个独立的模块中(类)
信息隐藏,尽可能隐藏对象的数据和功能的实现细节

封装的好处:
提高组件的重用性,把公用功能放到一个类中,谁需要该功能,直接调用即可
保证数据的安全性,防止调用者随意修改数据

2、JavaBean规范

JavaBean是一种某些符合条件的特殊类,但是必须遵循一定的规范:
1、类必须使用public修饰
2、必须保证有公共无参数构造器。即使手动提供了带参数的构造器,也得手动提供无参数构造器
3、字段使用private修饰(私有化)
4、每个字段提供一对getter和setter方法

getter方法:仅仅用于返回某一个字段的值;如果操作的字段是boolean类型的,此时是is方法,把 getName 变成 isName。

public String getName(){ return name; //返回name字段存储的值 }

setter方法:仅仅用来给某一个字段设置值,实际开发过程中,可以融入校验逻辑。

public void setName(String n){ name = n; //把传过来的参数n的值,存储到name字段中 }

注意:每一个字段都得使用private修饰,并提供一对getter/setter方法。
IDEA工具可以自动生成标准的getter/setter
IDEA快捷键:Alt+ins,选择getter/setter

3、访问权限修饰符

访问修饰符,决定了有没有权限访问某个成员(资源)。

封装其实就是要让有些类看不到另外一些类中定义的字段和方法。Java提供了不同的访问权限修饰符来限定类中的成员让谁可以访问到。
访问修饰符
· private:表示当前类私有的,类访问权限,只能在本类中操作,离开本类之后就不能直接访问
· 不写(缺省):表示当前包私有,包访问权限,定义和调用只能在同一个包中,才能访问
· protected:表示子类访问权限,同包中的可以访问,即使不同包但是有继承关系也可以访问
· public:表示公共的,可以在当前项目中任何地方访问

4、this关键字

解决成员变量和局部变量的二义性
在这里插入图片描述
使用 this.变量名 的语法,此时访问的就是成员变量

5、构造器和setter方法的选用

构造器和setter方法都可以给对象设置数据:
构造器,在创建对象的时候设置初始数据,只能初始化一次。
setter方法,创建对象后再设置初始数据,可以设置多次。

三、继承

面向对象的继承思想,可以解决多个类存在共同代码的问题:
· 被继承的类,称之为父类
· 继承父类的类,称之为子类
· 父类:存放多个子类共同的字段和方法
· 子类:存放自己特有的(独有的)字段和方法
经过继承后,子类拥有了父类的特征和行为,子类拥有了父类的字段和方法

1、继承语法

语法

public class 父类名{ 
	// 存放多个子类共同的字段和方法 
}

public class 子类名 extends 父类名{ 
	// 存放自己特有的(独有的)字段和方法 
}

Java中类只支持单继承,但是支持多重继承。也就是说一个子类只能有一个直接的父类,父类也
可以再有父类

如果父类中的成员使用public和protected修饰,子类都能继承.
如果父类和子类在同一个包中,使用缺省访问修饰的成员,此时子类可以继承到
如果父类中的成员使用private修饰,子类继承不到。private只能在本类中访问
父类的构造器,子类也不能继承,因为构造器必须和当前的类名相同

一句话:子类继承父类的非私有成员(字段和方法),但构造器除外
在这里插入图片描述

2、方法覆盖

当子类继承父类的方法不能满足自身需要时,子类就可以根据自身需要对父类的同名方法进行重
写。子类存在一个和父类一模一样的方法时,我们就称之为子类覆盖了父类的方法,也称之为重写
(override)。

方法覆盖的细节:

  1. 方法签名必须相同 (方法签名= 方法名 + 方法的参数列表)
  2. 子类方法的返回值类型:要么和父类方法的返回类型相同,要么是父类方法返回值类型的子类
  3. 子类方法的访问权限 >= 父类方法访问权限 ;如果父类方法是private,子类方法不能重写。==> 重写建立在继承的基础上,没有继承,就不能重写。
  4. 子类方法中声明抛出的异常小于或等于父类方法声明抛出异常类型

精华:直接拷贝父类中方法的定义粘贴到子类中,再重新编写子类方法体,打完收工

覆盖中super关键字

在子类中的某一个方法中需要去调用父类中被覆盖的方法,此时得使用super关键字。

public class Ostrich extends Bird{ 
	public void fly() { 
		System.out.println("拍拍翅膀,快速奔跑..."); 
		}
	public void say() { 
		super.fly();//调用父类被覆盖的方法 
		fly();//调用本类中的方法 
	} 
}

如果调用被覆盖的方法不使用super关键字,此时调用的是本类中的方法。
1、super关键字表示父类对象的意思,更多的操作,后面再讲。
2、super.fly() 可以翻译成调用父类对象的fly方法。

3、抽象

任何事物都是具有普遍性和特殊性的,抽象类就是将生活中具体的事物进行抽象化,一般化,普遍化然后在程序中表现出来的一种形式。

用来捕捉子类的通用特性的,是被用来创建继承层级里子类的模板
作为子类的模板,要有子类,具有子类相同特性,现实方法交给子类重写

抽象类

使用abstract修饰的类

public abstract class 类名 { 
}

抽象类能够作为一种条件限制子类
抽象类中无法创建对象

抽象类的特点:
抽象类不能创建对象,调用没有方法体的抽象方法没有任何意义
抽象类中可以同时拥有抽象方法和普通方法
抽象类要有子类才有意义,子类必须实现父类的所有的抽象方法,除非子类也是抽象类

抽象方法

使用abstract修饰的方法

public abstract 返回类型 方法名(参数);

抽象方法的特点:
使用abstract修饰,没有方法体,留给子类去覆盖
抽象方法必须定义在抽象类或接口中

Object类

Object本身表示对象类的意思,是Java中的根类,要么是一个类的直接父类,要么就是一个类的间接父
类。

public class A{ 
}
//其实等价于 
public class A extends Object{ 
}

因为所有类都是Object类的子类, 所有类的对象都可以调用Object类中的方法,常见的方法:

boolean equals(Object obj):拿当前调用该方法的对象和参数obj做比较
在Object类中的equals方法和“ == ”符号相同,都是比较对象是否是同一个的存储地址。

==

== 符号到底比较的是什么:
比较基本数据类型:比较两个值是否相等
比较对象数据类型:比较两个对象是否是同一块内存空间
每一次使用new关键字,都表示在堆中创建一块新的内存空间。

四、接口

接口是一种体现了约定和实现相分离的思想的规范;接口也体现低耦合思想(在开发过程中,如果想要解耦,一定要想到接口)

接口定义和多继承性

接口可以认为是一种特殊的类,但是定义类的时候使用class关键字,定义接口使用interface关键字。

public interface 接口名{ 
	//抽象方法1(); 
	//抽象方法2(); 
}// 接口命名规范:大写的驼峰命名法。

在java中,接口也可以继承,一个接口可以继承多个接口,也就是说一个接口可以同时继承多个接口

接口实现类

因为接口中的方法是抽象的,没有方法体,所以接口是不能创建对象的,此时必须定义一个类去实 现接口,并覆盖接口中的方法,这个类称之为实现类,实现类和接口之间的关系称之为实现关系

public class 类名 implements 接口名{ 
	// 覆盖接口中抽象方法
 }

实现类实现接口后,必须实现接口中的所有抽象方法,完成功能代码,此时接口和实现类之间的关系:
···接口:定义多个抽象方法,仅仅定义有哪些功能,却不提供实现。
···实现类:实现接口,实现接口中抽象方法,完成功能具体的实现。

根据方法覆盖原则:子类方法的访问修饰符必须大于等于父类方法的访问修饰符,接口中的方法都是
public修饰的,所以实现类中的方法只能使用public修饰。

实现类可以继承父类,可以同时实现一个或多个接口,继承在前,实现在后。
接口是一种引用数据类型,可以用来声明变量,并接收(引用)所有该接口的实现类对象

eg : 定义一个青蛙类(Frog)继承于动物类(Animal),同时实现于会走路(IWalkable),会游泳
(ISwimable)的接口,

public class Frog extends Animal implements ISwimable,IWalkable{ 
	public void walk() { 
		System.out.println("跳啊跳..."); 
	}
	public void swim() { 
		System.out.println("游啊游.."); 
	} 
}

接口总结

接口表示一种规约(规范、标准),它里面定义了一系列抽象方法(功能),它可以被多个类实
现。
实现类实现接口,必须实现接口中的所有抽象方法。我们经常说:接口约定了实现类应该具备的能
力。

// IWalkable接口约定了walk()的规范 
public interface IWalkable { 
	void walk(); 
}
//Person必须实现接口中的所有抽象方法 => 实现类具有接口中定义的功能 
public class Person implements IWalkable { 
	@Override 
	public void walk() { 
		System.out.println("人类走路..."); 
	} 
}
//=> 接口约定了实现类应该具备的功能

五、多态

当通过同一引用类型的变量,由于引用的实例不同,对同一行为产生的结果不同。

多态思想

在继承关系,是一种 is A 的关系,也即 什么是什么 ,也就说子类是父类的一种特殊情况,有如下代
码:
例如:如果Student 继承于 Person,我们就可以说,学生 is 人类


public class Animal{} 
public class Dog extends Animal{} 
// Dog is a Animal 
public class Cat extends Animal{} 
// Cat is a Animal

那么我们可以认为狗和猫都是一种特殊的动物,那么可以使用动物类型来表示狗或猫。

Dog d = new Dog(); //创建一只狗对象,赋给子类类型变量 
Animal a = new Cat(); //创建一只猫对象,赋给父类类型变量

此时对象(a)具有两种类型:
编译时类型:声明对象变量的类型——>Animal
运行时类型:对象的真实类型 ——>new Dog

当编译类型和运行类型不一致的时候,此时多态就产生了:
注意:编译类型必须是运行类型的父类或接口。

所谓多态,简单地理解 , 表示一个对象具有多种形态。

操作继承关系

父类 变量名 = new 子类();
变量名.方法();

Animal 类
public class Animal { 
	public void shout() { 
		System.out.println("Animal...shout..."); 
	} 
}

Cat 类·
public class Cat extends Animal{ 
	public void shout() { 
		System.out.println("妙妙妙..."); 
	}
}

Dog类
public class Dog extends Animal{ 
	public void shout() { 
		System.out.println("旺旺旺..."); 
	} 
}

测试类
public class AnimalDemo { 
	public static void main(String[] args) { 
	// 声明一个动物 
	Animal animal = null; 
	// animal引用了Cat对象,程序运行过程中,animai的真实类型是一只猫 
	animal = new Cat(); 
	animal.shout(); 
	// animal引用了Dog对象,程序运行过程中,animai的真实类型是一只狗 
	animal = new Dog(); 
	animal.shout(); 
	} 
}

result:
妙妙妙... 
旺旺旺...

父类引用变量指向于子类对象,调用方法时实际调用的是子类的方法。

操作实现关系

接口 变量名 = new 实现类();
变量名.方法();

ISwimable 接口:
public interface ISwimable { 
	void swim(); 
}

frish实现类
public class Fish implements ISwimable{ 
	public void swim() { 
		System.out.println("游啊游..."); 
	} 
}

Person类
public class Person implements ISwimable { 
	@Override 
	public void swim() { 
		System.out.println("喝了很多水,才学会在水里游泳"); 
	} 
}

测试类:
public class FishDemo { 
	public static void main(String[] args) { 
	// 声明一个ISwimable接口类型的变量 
	ISwimable swimable = null; 
	swimable = new Person(); 
	swimable.swim(); 
	swimable = new Frog(); 
	swimable.swim(); 
	} 
}

运行结果:游啊游...

接口引用变量指向实现类对象,调用方法时实际调用的是实现类实现接口的方法。

多态时方法调用问题

把子类对象赋给父类变量,此时调用方法:

Animal animal = new Cat();
animal.shout();

那么 animal 对象调用的shout方法,是来自于Animal中还是Cat中?
在这里插入图片描述
如图:先判断shout方法是否在父类Animal类中:
找不到:编译报错
找 到:再看shut方法是否在子类Cat类中:
找不到:运行父类方法
找 到:运行子类方法(这个才是真正的多态方法调用)

多态中的类型转换

类型转换
自动类型转换:把子类对象赋给父类变量(多态)

Animal a = new Dog();
Object obj = new Dog(); //Object是所有类的根类

强制类型转换:把父类类型对象赋给子类类型变量。

子类类型 变量 = (子类类型)父类对象;

前提:该对象的真实类型应该是子类类型,在开发过程中,如果需要调用子类特有的方法时,一定要进行强制类型转换

instanceOf

instanceof 运算符:判断该对象是否是某一个类/父类/接口的实例,在开发中运用不是很多

语法格式: boolean b = 对象A instanceof 类B; //判断 A对象是否是 B类的实例?如果是,返回true

总结

提示:这里对文章进行总结:

设计一个对成员变量的访问做出一些限定,不允许外界随意访问类时,这就需要实现类的封装。
类的封装,就是将类中的属性私有化,即用private关键字来修饰,使得私有属性只能在它所在的类中被访问。

实际开发中一些类存在很多相识的变量和方法,创建公共父类有利于代码的重复利用

面向接口编程,体现的就是多态,其好处:把实现类对象赋给接口类型变量,屏蔽了不同实现类之
间的实现差异,从而可以做到通用编程。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值