Java基础学习五 面向对象
2021-05-27 本文已影响0人
SimonLike
面向对象
采用面向对象的方式开发一个软件,生命周期当中【整个生命周期中贯穿使用OO面向对象方式】:
面向对象分析:OOA
面向对象设计:OOD
面向对象编程:OOP
类和对象的概念
- 什么是类?
- 类在现实世界当中是不存在的,是一个模板,是一个概念。是人大脑思考抽象的结果。
- 类代表了一类事物
- 在现实世界当中,对象A与对象B之间具有共同特征,进行抽象总结出一个模板,这个模板被称为类。
- 什么事对象?
- 对象是实际存在的个体。现实世界当中实际存在。
- 描述一下整个软件开发的过程:
- 程序员先观察现实世界,从现实世界当中寻找对象
- 寻找了N多个对象之后,发现所有的对象都有共同特征。
- 程序员在大脑中形成了一个模板【类】。
- Java程序员可以通过java代码来描述一个类。
- Java程序中有了类的定义。
- 然后通过类就可以创建对象。
- 有了对象之后,可以让对象直接协作起来形成一个系统。
- 类 --【实例化】--> 对象
- 对象又被称为:实例/instance
- 对象 --【抽象】-->类
1. 面向过程和面向对象的区别
- 面向过程:主要关注点是:实现的具体过程,因果关系【集成显卡的开发思路】
- 优点:对于业务逻辑比较简单的程序,可以达到快速开发,前期投入成本低。
- 缺点:采用面向过程的方式开发很艰难解决非常复杂的业务逻辑,另外面向过程的方式导致软件元素之间的“耦合度”非常高,只要其中一环出问题,整个系统受到影响,导致最终的软件“扩展力”差。另外,由于没有独立体的概念,所以无法达到组件复用。
- 面向对象:主要关注点是:主要关注对象【独立体】能完成哪些功能。【独立显卡的开发思路】
- 优点:耦合度低,扩展力强。更容易解决现实世界当中更复杂的业务逻辑。组件复用性强。
- 缺点:前期投入成本较高,需要进行独立体的抽取,大量的系统分析与设计。
- c语言是纯面向过的、c++半面向对象、Java纯面向对象
- 现在出现的一些新的编程语言多数都是面向对象的。人在认识现实世界的时候已面向对象的方式。
- 面向对象更符合人的思维方式
2. 面向对象的三大特征
2.1封装
代码加注释讲解方式,其中Students类可以新建一个java类使用。
/**
* 为什么要封装?封装有什么好处?
* 封装的好处:
* 1、封装之后,对于那个事物来说,看不到这个事物比较复杂的那一面,只能看到该事物简单的那一面。
* 复杂性封装,对外提供简单的操作入口。照相机就是一个很好的封装案例,照相机的实现原理非常复杂,
* 但是对于使用照相机的人来说,操作起来是非常方便的。
*
* 2、封装之后才会形成真正的"对象",真正的"独立体"。
*
* 3、封装就意味着以后的程序可以重复使用。并且这个事物适应性比较强,在任何场合都可以使用。
*
* 4、封装之后,对于事物本身,提高了安全性。【安全级别高】
*
*/
public class HelloWorld {
public static void main(String[] args) {//表示定义一个公开的静态的主方法 ps:程序执行入口
Students peo = new Students();
// 访问实例变量的语法格式:
// 修改数据:引用.变量名 = 值
peo.setName("张三");
peo.setNoID(1233);
peo.setAge(16);
peo.setSex(true ? "男" : "女");
peo.setAddr("深圳");
// 读取数据:引用.变量名
System.out.println(peo.getName());
System.out.println(peo.getNoID());
System.out.println(peo.getAge());
System.out.println(peo.getSex());
System.out.println(peo.getAddr());
}
}
/**
* 封装的步骤
* 1,所以的属性私有化,使用private关键字进行修饰,private表示私有的,修饰所有数据只能在本类中访问。
* 2,对外提供简单的操作入口,也就是说以后外部程序要想访问属性,必须通过这些简单的入口进行访问。
* - 对外提供两个公开的方法,分别是set方法和get方法
* - 修改这个属性的值,调用set方法
* - 读取这个属性的值,调用get方法
* 3,set方法的命名规范
* public void set+属性首字母大写(形参){}
* 4,get方法的命名规范
* public void get+属性首字母大写(){ return 属性;}
*
* 一种属性常访问的时候有几种访问形式?
* - 第一种方式:读取这个属性的值,读取get
* - 第二种方式:修改这个属性的值,读取set
*
* setter和getter 方法没有static关键字
* 有static关键字修饰的方法如何调用:类名.方法名(实参)
* 没有static关键字修饰的方法如何调用:引用.方法名(实参)
*
*/
class Students {
int noID;// 学号
String name; //姓名
private int age; //年龄
String sex; //性别
String addr; // 地址
//=================setter=======================
public void setAge(int age) {
if (age<0|age>130) {
System.out.println("年龄不合法");
return ;
}
this.age = age;
}
public void setNoID(int noID) {
this.noID = noID;
}
public void setName(String name) {
this.name = name;
}
public void setSex(String sex) {
this.sex = sex;
}
public void setAddr(String addr) {
this.addr = addr;
}
//=================getter=======================
public int getAge() {
return age;
}
public int getNoID() {
return noID;
}
public String getName() {
return name;
}
public String getSex() {
return sex;
}
public String getAddr() {
return addr;
}
}
2.2继承
2.2.1 继承模块
代码加注释讲解方式,其中CreditAccounts、Accounts、FF类可以新建java类使用。
/**
* 关于java语言当中的继承:
* 1、继承是面向对象三大特征之一
* 2、继承基本作用:代码复用。但是继承最重要的作用是:有了继承才有以后的"方法覆盖"和"多态机制"。
* 3、继承语法格式:
* [修饰符列表] class 类名 extends 父类名{
* 类体 = 属性 + 方法
* }
* 4、java语言当中的继承只支持单继承,一个类不能同时继承很多类,只能继承一个类。
* 5、关于继承中的一些术语
* B类继承A类,其中
* A类称为:父类、基类、超类、superclass
* B类称为:子类、派生类、subclass
* 6、在java语言当中子类继承父类都继承哪些数据?
* - 私有的不支持继承
* - 构造方法不支持继承
* - 其他数据都可以被继承
* 7、虽然java语言当中只支持单继承,但是一个类也可以间接继承其他类,例如:
* C extends B{
* }
* B extends A{
* }
* A extends T{
* }
* C直接继承B类,但是C类间接继承 T A 类
* 8、java语言中假如一个类没有显示继承任何类,该类默认继承JavaSE库当中提供的java.lang.Object类。
* java语言中任何一个类中都有Object类的特征。
*
*/
public class HelloWorld {
public static void main(String[] args) {//表示定义一个公开的静态的主方法 ps:程序执行入口
// 对象继承 赋值 取值
CreditAccounts ca = new CreditAccounts();
ca.setActno("abc0001");
ca.setBalance(20000.00);
ca.setCredit(0.99);
System.out.println(ca.getActno()+ "," + ca.getCredit() + "," + ca.getCredit() );
// 间接继承 方法调用
ca.doSome();
}
}
class CreditAccounts extends Accounts{
private double credit;
public CreditAccounts() {
}
public CreditAccounts(double credit) {
this.credit = credit;
}
public double getCredit() {
return credit;
}
public void setCredit(double credit) {
this.credit = credit;
}
}
class Accounts extends FF{
private String actno;
private double balance;
public Accounts() {
}
public Accounts(String actno, double balance) {
this.actno = actno;
this.balance = balance;
}
public String getActno() {
return actno;
}
public void setActno(String actno) {
this.actno = actno;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
}
class FF{
public void doSome(){
System.out.println("do Some");
}
}
2.2.2 方法的覆盖
代码加注释讲解方式,其中Animal、Cat、Bird类可以新建java类使用。
/**
* 关于java语言当中方法的覆盖:
* 1,方法覆盖有被称为方法重写,英文:override[官方的]/overwrite。
* 2、什么时候使用方法重新?
* 当父类中的方法已经无法满足当前子类的业务需求,
* 子类有必要将父类中继承的方法进行重新编写,
* 这个重新编写的过程称为方法重写/方法覆盖。
* 3,什么条件满足之后方法会发生重写?【代码满足什么条件后,就构成方法的覆盖?】
* 方法重写发生在具有继承关系的父子类之间
* 返回值类型相同,方法名相同,形参列表相同
* 访问权限不能更低,可以更高。
* 抛出异常不能更多,可以更少。
* 4,注意:
* 私有方法不能继承,所有不能覆盖。
* 构造方法不能继承,所以不能覆盖。
* 静态方法不存在覆盖。
* 覆盖只针对方法,不谈属性。
*
*
*/
public class HelloWorld {
public static void main(String[] args) {//表示定义一个公开的静态的主方法 ps:程序执行入口
//创建动物对象
Animal a = new Animal();
a.move();
Cat c = new Cat();
c.move();
Bird b = new Bird();
b.move();
}
}
class Bird extends Animal{
public void move(){
System.out.println("鸟儿在飞翔");
}
}
class Cat extends Animal{
public void move(){
System.out.println("猫在走猫步");
}
}
class Animal{
public void move(){
System.out.println("动物在移动");
}
}
2.3多态
关于java语言当中的多态语法机制(概念):
向上转型(upcasting) 子类型-->父类型 称为:自动类型转换。 向下转型(downcasting) 父类型-->子类型 称为:强制类型转换。【需要加强制类型转换符】 无论向上转型还是向下转型,两种类型之间必须要有继承关系,否则程序是无法编译通过的。
代码加注释讲解方式,其中Animal、Cat、Bird类可以新建java类使用。
public class HelloWorld {
public static void main(String[] args) {//表示定义一个公开的静态的主方法 ps:程序执行入口
//使用多态语法机制
// =====父类引用指向子类型对象【多态】 向上转型 =============================================
/**
* Animal和Cat之间存在继承关系,Animal是父类,Cat是子类。
* Cat is a Animal
*
* new Cat()创建对象的类型是Cat,a2这个引用的数据类型是Animal,进行了类型转换。
* 子类型转换成父类型,称为向上转型/upcasting。
*
* java语言允许:父类型引用指向子类型对象。
*
*/
Animal a2 = new Cat();
/**
* java语言是先分析编译阶段,在分析运行阶段,编译无法通过,是无法运行的。
*
* 编译阶段编译器检查a2这个引用的数据类型为Animal,由于Animal.class字节码当中有
* move()方法,所以编译通过了。这个过程我们成为静态绑定,编译阶段绑定。只有静态绑定
* 成功之后才有后续的运行。
*
* 在程序运行阶段,jvm堆内存当中真实创建的对象是Cat对象,那么以下程序在运行阶段一定会
* 调用Cat对象的move()方法,此时发生了程序的动态绑定,运行阶段绑定。
*
* 无论Cat类有没有重写move()方法,运行阶段一定调用的是Cat对象的move()方法,因为底层
* 真实对象就是Cat对象。
*
* 父类型引用指向子类型对象,这种机制导致程序存在"编译阶段绑定"和"运行阶段绑定"两种不同的形态/状态,
* 这种机制称为:多态语法机制。
*
*/
a2.move();// 输出:猫在走猫步
/**
* 分析以下程序为啥不能调用?
*
* 因为编辑阶段编译器检查到a2的类型是Animal类型,从Animal.class字节码文件当中查找catchMouse()
* 方法,最终没找到该方法,导致静态绑定失败,也就是说编译失败了。别谈运行了。。
*/
//a2.catchMouse();
//===== 父类引用指向子类型对象【多态】 向下转型【只有当访问子类对象当中的特有方法】===================================
Animal a3 = new Bird();
/**
* 以下程序编译时没问题的,因为编译器检查到a3的数据类型是Animal, Animal和Cat是存在继承关系,并且Animal
* 是父类,Cat是子类型,父类装换成子类型叫做向下转型,语法合格。
*
* 程序虽然编译通过了,但是程序运行阶段会出现异常,因为jvm堆内存当中真实存在的对象是Bird类型,Bird对象无法
* 转换成Cat对象,因为这两种类型不存在继承关系,会出现异常:java.lang.ClassCastException。
*/
//Cat c3 = (Cat) a3;
/**
* 1,以上异常只有在强制类型转换的时候会发生,也就是说"向下转型"存在隐患(编译通过,但运行出错了)
* 2,向上转型只要编译通过,运行一定不会出现问题,
* 3,向下转型编译通过,运行可能出现问题,如何避免出现ClassCastException异常呢?
* 使用instanceof运算符可以避免出现以上的异常。
* 4,instanceof运算符的使用
* 语法结构:(引用 instanceof 数据类型名)
* 运算符执行结果类型是布尔类型,true/false
* 5,java规范中要求:在进行强制类型转换之前,建议采用instanceof运算符进行判断,避免ClassCastException异常发生。
*
*/
if(a3 instanceof Cat){
Cat c3 = (Cat) a3;
c3.catchMouse();//调用子类对象中特有的方法
}else if (a3 instanceof Bird) {
Bird b2 = (Bird) a3;
b2.fly();//调用子类对象中特有的方法
}
}
}
class Bird extends Animal{
public void move(){
System.out.println("鸟儿在飞翔");
}
public void fly(){
System.out.println("鸟儿在fly");
}
}
class Cat extends Animal{
public void move(){
System.out.println("猫在走猫步");
}
public void catchMouse(){
System.out.println("猫在抓老鼠");
}
}
class Animal{
public void move(){
System.out.println("动物在移动");
}
}
3. 面向对象-->定义类和对象
代码加注释讲解方式,其中Students类可以新建一个java类使用。
- 局部变量在栈内存中存储
- 成员变量中的实例变量实例变量在堆内存的java对象内部存储
public class HelloWorld {
public static void main(String[] args) {//表示定义一个公开的静态的主方法 ps:程序执行入口
// 通过一个类可以实例化N个对象
// 实例化对象语法:new 类名();
// new是java语言当中的一个运算符。
// new运算符的作用是创建对象,在jvm堆内存当中开辟新的内存空间
// 方法区内存:在类加载的时候,class字节码代码片段被加载到该内存空间当中。
// 栈内存(局部变量):方法代码片段执行的时候,会给该方法分配内存空间,在栈内存中压栈。
// 堆内存:new的对象在堆内存中存储。
// Student是一个引用类型
// peo是一个变量名
// new Student()是一个学生对象
// peo是一个局部变量【在栈内存中存储】
// 什么是对象?new运算符在堆内存中开辟内存空间称为对象。
// 什么是引用?引用是一个变量,只不过这个变量中保存了另一个java对象的内存地址。
// java语言当中,程序员不能直接操作堆内存,java中没有指针;不像C语言
// java语言当中,程序员只能通过"引用"去访问堆内存当中对象内部的实例变量。
Students peo = new Students();
// 访问实例变量的语法格式:
// 读取数据:引用.变量名
System.out.println(peo.name);
System.out.println(peo.noID);
System.out.println(peo.sex);
System.out.println(peo.age);
System.out.println(peo.addr);
// 修改数据:引用.变量名 = 值
peo.name = "张三";
peo.noID = 1233;
peo.age = 16;
peo.sex = true ? "男" : "女";
peo.addr = "深圳";
// 再创建一个Student对象
Students st = peo;
System.out.println(st.name);
System.out.println(st.noID);
System.out.println(st.sex);
System.out.println(st.age);
System.out.println(st.addr);
}
}
/*学生类
学生类是一个模板
描述所有学生的共同特征【状态+行为】
当前类只描述学生的状态信息【属性】
*/
class Students {
// 类体 = 属性 + 行为
// 属性【存储数据采用变量的形式】
// 由于变量定义在类体当中,方法体之外,这种变量称为成员变量
// 所有学生都有学号信息
// 但是每一个学生的学号是不同的
// 所有访问这个学号必须先创建对象,通过对象去访问学号信息
// 学号信息不能直接通过"类"去访问,所以这种成员变量有被叫做:实例变量
// 对象有被称为实例,实例变量有被称为对象变量。【对象级别的变量】
// 不创建对象,这个noID变量的内存空间是不存在的,只有创建了对象,这个noID的变量内存空间才会创建。
int noID;// 学号
String name; //姓名
int age; //年龄
String sex; //性别
String addr; // 地址
}
4. 面向对象-->构造方法
- 构造方法有被称为构造函数/构造器/Constructor
- 构造方法结构:
- [修饰符列表] 构造方法名(形式参数列表){ 构造方法体;}
- 回顾普通方法的语法结构:
- [修饰符列表] 返回值类型 方法名(形式参数列表){ 方法体;}
- 对于构造方法来说,"返回值类型"不需要指定,并且也不能写void;只要写上void,这个方法就成为普通方法了。
- 构造方法的方法名必须和类名保持一致。
- 构造方法的作用?
- 构造方法存在的意义是,通过构造方法的调用,可以创建对象。
- 创建对象的同时,初始化实例变量的内存空间。
- 构造方法应该怎么调用?
- 普通方法是这样调用的:方法修饰符中有static的时候:类名.方法名(实参列表)、方法修饰列表中没有static的时候:引用.方法名(实参列表)
- new 构造方法名(实参列表)
- 构造方法调用执行之后,有返回值吗?
每一个构造方法实际上执行结束之后都有返回值,但是这个"return 值;"这样的语句不用写。并且返回值类型是构造方法所在类的类型。由于构造方法的返回值类型是类本身,所以返回值类型不需要填写。 - 当一个类中没有定义任何构造方法的话,系统默认给该类提供一个无参数的构造方法,这个方法被称为缺省构造器。
- 当一个类显示的构造方法定义出来了,那么系统则不再默认为这个类提供缺省构造器。建议开发中手动为当前类提供无参数构造方法。因为无参数构造方法太常用了。
- 构造方法支持重载机制。在一个类中编写多个构造方法,多个构造方法显然已构成方法重载机制。
demo代码示例:
public class HelloWorld {
public static void main(String[] args) {//表示定义一个公开的静态的主方法 ps:程序执行入口
new Students();
}
}
class Students {
//构造方法
public Students() {
System.out.println("构造方法");
}
}
5. 面向对象-->参数的传递
-
对象和引用:
- 对象:目前在使用new运算符在堆内存中开辟的内存空间称为对象。
- 引用:是一个变量,不一定是局部变量,还可能是成员变量。引用保存了内存地址,指向了堆内存当中的对象。
-
所有访问实例相关的数据,都需要通过"引用."的方式访问,因为只有通过引用才能找到对象。
-只有一个空的引用,访问对象的实例相关的数据会出现空指针异常。 -
参数的传递
-方法调用的时候,涉及参数传递问题,传递的时候,java只遵循一种语法机制,就是将变量中保存的"值"传递过去了,只不过有的时候这个值 是一个字面值,有的时候这个值是另一个java对象的内存地址。
demo代码示例:
public class HelloWorld {
public static void main(String[] args) {//表示定义一个公开的静态的主方法 ps:程序执行入口
User u = new User(20);
// 传递u给add方法的时候,实际上传递的是u变量中保存的值,只不过这个值是一个java对象的内存地址。
add(u);//等同于 add(0x....);
}
public static void add(User a){
a.age++;
System.out.println("add---->" + a.age);
}
}
class User{
int age;//实例变量
public User(int i){
age = i;
System.out.println("age---->" + age);
}
}
上篇:Java基础学习四 方法
下篇:Java基础学习六 关键字