首先先看什么是面向过程
我们在用代码提现一个需求的时候,首先会先确认我们要做什么,其次再分析我们要用那种方式去做,最后用代码去展示出来.这个从需求到实现的过程被称为面向过程.在此流程中,我们扮演的是一个执行者.
再来看什么是面向对象
同样一个需求,在面向对象中,我们可以创建一个对象去分析,去实现,从而我们可以忽略它的所有过程,只关注结果.
生活中的面向对象:
洗衣服,我们可以交给洗衣机洗,交给对象去晾衣服,我们最后只需要穿上干净的衣服即可.此时,洗衣机和对象,就是我们来做事的对象;生活中有许多对象,万物皆可对象.
目录
面向对象的特点:
1)将我们从执行者变成指挥者.(角色发生了转换)
2)将复杂的事物简单化
3)更加的符合我们的思想习惯
面向对象的三大特征
封装,继承,多态
封装
就是将一个事物封存起来,不能被外界直接看到(访问)
概念:将一个类的成员变量私有化,外界不能直接访问,但是可以通过一些公共的访问方法来进行间接访问.
用private关键字对成员变量/成员方法进行修饰.(封装关键字)
封装的好处:
隐藏实现细节,提供公共访问方式;
提高代码的复用性;同时也提高了安全性.
//代码体现封装
class Demo{
//用private将姓名和年龄进行封装
private String name;
private int age;
//此时姓名和年龄不能被外界直接访问,需要用到公共访问方法
//公共访问方法 setXXX()和getXXX();
public void setName(){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(){
this.age = age;
}
public int getAge(){
return age;
}
}
//测试类
class Test{
public static void main(String[] args){
//创建Demo对象
Demo d = new Demo();
//用对象.set(XXX)方法对成员变量进行赋值
d.setName = "zhangsan";
d.setAge = 20;
//在输出语句中用对象.get(XXX)获取成员变量进行输出
System.out.println("姓名:"+d.getName+" 年龄:"+d.getAge);
}
}
继承
生活中的继承:儿子继承父亲的遗产
将一些类的共性的内容提取出来单独放在一个类中,让这个独立的类和其他类产生一种关系.单独的这个类称为父类;这多个类可以称为子类或派生类.
子类在继承父类的同时还会有自己特有的一些功能或属性
通过extends关键字可以实现类与类之间的继承
格式:class 子类名 extends 父类名{}
//代码体现继承关系
class Fu{
//父类的成员变量和成员方法
String name;//姓名
String sex;//性别
int age;//年龄
public void eat(){
//方法体
System.out.println("输入想输出的话");
}
public void sleep(){
System.out.println("同上");
}
//父类的构造方法
public Fu(){
System.out.println("我是无参构造方法");
}
//有参构造方法
public Fu(String name,String sex,int age){
this.name = name;
this.sex = sex;
this.age = age;
}
}
//Zi类继承于Fu类,使用extends关键字完成继承
class Zi extends Fu{
//子类自己的成员变量
String gameName ;//游戏名
//继承父类的所有属性和方法
//子类的构造方法
public Zi(){
super();
System.out.println("我是子类无参构造方法");
}
//有参构造方法
public Zi(String name,String sex,int age,String gameName){
super();
this.gameName = gameName;
}
//子类特有的一些功能
public void playGame(){
System.out.println("子类特有的功能");
}
//......
}
//测试类
class Test{
//main方法,程序的入口
public static void main(String[] args){
//创建子类对象z
Zi z = new Zi();
//对子类的成员变量进行赋值
z.name = "张三";
z.sex = "男";
z.age = 20;
//上半部分成员变量继承自父类
//下为子类特有的成员变量
z.gameName = "吃鸡";
//调用父类和子类特有的成员方法
z.eat();
z.sleep();
//子类特有的成员方法
z.playGame();
}
}
特点
1)在java中,继承(类与类之间)只支持单继承,不支持多继承!
2)虽然Java中,继承不支持多继承,但是可以多层继承
继承的好处
提高了代码的复用性;
提高了代码的可维护性;
让类与类之间产生了练习,是多态的前提条件.
加入继承之后类的成员访问问题:
分两种情况:
1)子类中和父类成员变量名称不一致的情况:比较简单,分别访问即可
2)子类中和父类中成员变量名称一致的情况:遵循"就近原则"
就近原则
子类和父类成员变量名称相同时子类访问成员变量会先从子类的局部位置开始找,如果找不到
就开始从子类的成员位置中找如果还找不到就从父类中找,如果再找不到就报错.
注意事项
1)子类继承父类,不能继承父类的私有成员(成员变量,成员方法)
2)子类继承父类,不能继承父类的构造方法,但是可以通过super关键字来间接访问
3)子类不能继承父类的构造方法,但是可以通过super间接访问父类的构造方法,子类的所有构造方法默认访问父类的无参构造方法!
4)每一个子类的构造方法中的第一句话是默认存在的super() ; 可以不写(隐藏的)
多态
生活中的多态:人在不同时刻会有不同的状态
一个事务在不同时刻显示出的不同状态(在堆内存中的变化)
//代码体现多态
/*
多态的前提条件
存在继承关系
存在重写关系
父类引用指向子类对象
抽象多态和接口多态同理具体类多态
*/
class FuDemo{
public void eat(){
//方法体
}
}
class ZiDemo extends FuDemo{
public void eat(){
//方法体,对父类方法进行重写
}
public void game(){
//方法体,子类特有的行为
}
}
//测试类
class Test{
public static void main(String[] args){
//父类引用指向子类对象(向上转型)
FuDemo fd = new ZiDemo();
//向下转型,指向子类的父类引用赋给子类引用,目的为了能够调用子类特有的方法
ZiDemo zd = (ZiDemo)fd;
zd.eat();
zd.game();
}
}
多态的前提条件
1)必须存在继承关系
2)要有方法重写
3)需要存在:父类引用指向子类对象(向上转型)
多态的好处
1)提高了代码的扩展性
2)提高了代码的复用性,维护性(由继承关系保证)
多态的弊端
不能够访问子类的特有功能!
解决方案:
方式一: 可以创建具体类对象: 子类名 对象名 = new 子类名();
用对象名.访问子类的自己的功能;
方式二:
将父类的引用强制转换为子类的引用(向下转型)
格式:强制类型转换的格式!目标数据类型 变量名 =( 目标类型)父类引用;
好处:不需要重新new对象,在堆内存是比较节省空间的
使用向下转型的前提:
要使用向下转型,必须先使用向上转型.
多态的成员访问特点:
父类名 对象名 = new 子类名();(具体类多态)
抽象类名 对象名 = new 抽象子类名();(抽象多态)
接口名 对象名 = new 接口子实现类名();(接口多态)
1)成员变量:编译看左边,运行看左边
2)成员方法:(非静态的):编译看左边,运行看右边(因为存在方法的重写)
3)静态的成员方法:编译看左边,运行看右边
4)构造方法:由于存在继承关系,还需要分层初始化
方法重写:指的是非静态方法
注意事项:
向下转型使用不当,程序出现异常
产生一个ClassCastException:运行异常的一种,使用向下转型的时候类型不匹配导致的
三大特征中所涉及到的其他知识点
private关键字
是一个权限修饰符;
可以修饰类中的成员(成员变量和成员方法);
被private修饰的成员只能在本类中进行访问
setXXX(),getXXX()方法
setXXX()和getXXX()被称为公共访问方式.
setXXX()表示对用private修饰的成员变量进行访问并赋值.
getXXX()表示获取8被private修饰的成员变量的值.
成员变量与局部变量的区别
成员变量:在类中方法外的变量
局部变量:在方法中方法声明上的变量
1)书写位置不同:(概念中已描述)
2)内存中的位置不同
成员变量在堆内存中,局部变量在栈内存中
3)生命周期不同
局部变量随着方法的调用而存在,方法调用完毕而消失,成员变量随着对象的创建完毕而存在,随着对象被GC回收而消失
4)初始化不同
成员变量可以不进行初始化,而局部变量使用前必须初始化.
this关键字
用来区分成员变量和局部变量
this.变量名 :代表成员变量
this.变量名 = 变量名(局部变量);
将局部变量的值赋给成员变量.
super关键字
代表父类的空间标记(父类对象的地址值引用)(其实就是一个指向父类的工具)
this和super的区别
this.成员变量;访问的当期类的成员变量
super.成员变量;访问的父类的成员变量
this.成员方法名() ;访问的是否当前类的成员方法
super.成员方法名() ;访问的是父类的成员方法
this() :访问的是本类无参构造方法
this(xxx):访问的本类的有参构造方法
super():访问的是父类的无参构造方法
super(xxx):访问的父类的有参构造方法
构造方法
语法规则:
1)方法名必须和类名相同
2)无返回值类型,也没有void
3)可以指定参数,也可以不指定参数(即无参构造方法和有参构造方法)
作用
给对象的成员进行初始化
特点
1)当我们没有指定构造参数时,系统会自动添加无参的构造方法
2)构造方法可以重载
3)构造方法不能被继承
4)当我们指定了构造方法时,系统将不再添加无参构造方法
//代码体现构造方法
/*
1)方法名和类名相同
2)没有返回值类型,void也没有
3)有无参构造方法和有参构造方法
*/
class Demo{
String name;//成员变量
//无参构造方法
public Demo(){
System.out.pritnln("我是无参构造方法");
}
//有参构造方法
public Demo(String name){
System.out.println("我是有参构造方法");
}
}
为什么要访问父类的无参构造方法?
由于存在继承关系,创建的是子类对象,对子类初始化的时候(执行构造方法),可能会用到父类的数据,必须要让父类先进行初始化(先执行父类的构造方法),父类初始化完毕了,才是子类初始化(分层初始化!)
如果父类中没有提供无参构造方法?会怎么办
会编译报错,因为父类有存在有参构造方法,系统不会提供无参的,又由于子类的所有构造方法默认访问父类的无参,所以报错了!
解决方案:
1)手动给出父类的无参构造方法
2)可以让子类的所有构造方法,默认访问父类的有参
2.1)让子类构造方法中的第一句话是:super(xxx);
2.2)子类中所有构造方法的一个只要能够让父类初始化即可!
3)通过子类的有参构造方法,访问this()本类的无参构造方法,在通过本类的无参构造方法