面向对象【封装 继承 多态 关键字】
1、封装
1.1、概念
指隐藏对象的属性和实现细节,仅对外提供公共访问的方法。
1.2、优点
- 方便使用;
- 提高复用性;
- 提高安全性;
2、继承
2.1、概念
把很多类的相同特征
和行为
进行抽取,使用一个类描述,让多个类和这个类产生一种关系。这样就可以使多个类省略很多的代码,这个关系
就是继承,用extends
关键字表示
2.2、体系结构
多个具体的对象,不断地向上抽取共享的内容,最终形成了一个继承体系。
2.3、特点
- Java中只能
单继承
(单继承:一个子类只能继承一个父类),不能多继承(不能继承多个父类);
class SubDemo extends Demo{} //ok
class SubDemo extends Demo1,Demo2...//error
- 但Java可以
多重继承
(即A继承B,B继承C;C是B的父类,B是A的父类)
class A{}
class B extends A{}
class C extends B{}
定义继承需要注意:不要仅为了获取其他类中某个功能而去继承。
日常开发中小技巧:
多层继承出现的继承体系中,通常看父类中的功能,了解该体系的基本功能,建立子类对象即可使用该体系功能。
多重继承虽然能使子类同时拥有多个父类的特征,但是其缺点
也是很显著的,主要有两方面:
- 如果在一个子类继承的多个父类中拥有
相同名字
的实例变量
,子类在引用该变量时将产生歧义,无法判断应该使用哪个父类的变量。 - 如果在一个子类继承的多个父类中拥有
相同方法
,子类中有没有覆盖该方法,那么调用该方法时将产生歧义,无法判断应该调用哪个父类的方法。
2.4、优点或好处
- 继承的出现提高了代码的复用性;提高软件开发效率。
- 继承的出现让类与类之间产生了关系,提供了
多态
的前提。
2.5、子父类中的成员关系
成员变量:
在子类方法
中使用一个变量时:
- 先在方法的局部变量中找,有则使用;
- 若(1)中没有,则在本类的成员变量中找,有则使用;
- 若(2)中也没有,则在父类的成员变量中找,有则使用;没有,则报错。
成员方法:
用子类对象使用一个方法时:
先在子类中找,有则使用;
若(1)中没有,则在父类中找,有则使用;没有,则报错。
构造方法:
子类的实例化过程:
子类创建对象时,会先去创建父类的对象(默认是去调用父类的无参构造方法);
子类构造方法中,第一行默认是super() (子类需要继承父类的成员使用)。
当父类没有无参构造方法:
必须使用this或者super调用其他的构造方法。
重写和重载的区别:
重载:在同一个类中,方法名相同,参数列表不同,重载可以改变返回类型。
重写:在不同的类中(子父类),方法声明相同(返回类型,方法名,参数列表均相同)
2.6、this和super的区别
this:代表本类对象的引用
super:代表父类的存储空间
3、多态
3.1、前提
- 存在着继承或者实现关系;
- 有方法的重写;
- 父类(接口)引用指向子类(实现)对象。
3.2、思想
指挥同一批对象做事情。比如:带兵打仗,上课下课。
3.3、优点与弊端
优点:
多态的存在提高了程序的扩展性和后期的可维护性。
弊端:
虽然可以预先使用,但是访问父类中已有的功能,运行的是后期子类的功能内容,不能预先使用子类中定义的特有功能。
3.4、对象调用成员的特点
Fu f = new Zi();
成员变量:
编译看左边,运行看左边。
成员方法:
编译看左边,运行看右边。
静态方法:
编译看左边,运行看左边。
编译时期 | 运行时期 | |
---|---|---|
成员变量 | 左 | 左 |
成员方法 | 左 | 右 |
静态方法 | 左 | 左 |
4、关键字
4.1、super关键字
- 用于显示的调用父类中的构造函数;
- super()意为调用父类中不带参数的构造方法;
- super(xxx)意为调用父类中带参数的构造方法;
- super必须用在子类构造带的第一行。
4.2、this关键字
代表本类对象的一个引用,谁调用this所在的方法,this就代表谁。
使用场景:
- 用于区分同名成员变量和局部变量;
- 在定义函数时,该函数内部要用到调用该函数的对象时,因为此时对象还没建立,所以this代表此对象;
- 构造函数时调用,这个时候,this(参数)必须作为第一条语句存在。
格式:
this.属性 this() this.方法()
4.3、final关键字
其实可以按照final意思来理解:就是最终,不可变的意思,可以用于修饰类
,方法
和变量
。
特点:
- final修饰的类不能被继承;
- final修饰的方法不能被重写,父类的private成员方法是不能被子类方法覆盖的,因为private类型的方法默认是final类型;
- final修饰的变量是常量,只能赋值一次,且定义时候必须有初始值不能变;
- final修饰的引用类型变量,表示该引用变量的引用不能变,而不是引用所指的对象中的数据还是可以变化的;
- 内部类只能访问被final修饰的局部变量;
- final不能用于修饰构造方法。
注意:
当程序中一个数据是固定不变
的,这时为了增加阅读性,可以给该数据起个名字。为了保证这个变量的值不被修改,加上final
修饰,变量就为阅读性很强的常量。书写规范,被final
修饰的常量
名所有的字母都是大写的。如果由多个单词组成单词间通过 _
连接。
通常规范中:常量名称所有字母大写,若有多个单词组成,单词间使用下划线连接。
public static final 修饰的常量称为全局常量;
public static final double PI = 3.14159265358979323846;
public static final String APP_SEPARATOR = "/";
4.4、static关键字
4.4.1、作用
用来修饰成员变量和成员函数。
4.4.2、静态的特点
- 随着类的加载而加载;
- 优先于对象存在;
- 对所有对象共享;
- 可以直接被类型调用。
4.4.3、静态的注意事项
-
静态方法只能访问静态成员(原因:静态的内容是随着类的加载而加载的,先进内存)
-
静态方法中不能使用this,super关键字
-
main()方法是静态的
main
方法其实也静态的。因为main
是程序的入口,是提供给JVM使用的,当在dos
中输入java XXX
时,会启动JVM,同时JVM会加载以XXX为名称的这个class文件进内存。并扫描其中有没有main
方法。若有main方法JVM就会去调用这个main方法。JVM调用main方法,是不会创建对象的,没有对象怎么调用方法,这个方法只能被静态修饰
。JVM通过类名调用
的。
4.4.4、静态变量和成员变量的区别
调用方式不同:
静态变量所属与类
,也称为类变量
。
成员变量所属于对象
,也称为实例变量
(对象变量)。
存储位置不同:
静态变量存储于方法区中的静态区
中。
成员变量存储于堆内存
中。
(局部变量存在于栈内存中)
生命周期不同:
静态变量随着类的加载而加载,随着类的消失而消失。
成员变量随着对象的创建而在堆内存中出现,随着对象的消失而消失。
与对象的相关性:
静态变量是所有对象共享的数据。
成员变量是每个对象特有的数据。
4.4.5、静态的优势和弊端
优势:
对共享的数据进行单独空间的存储,节省内存;
可直接被类名调用。
弊端:
生命周期过长,随着类的消失而消失。
访问出现权限,即静态虽好但只能访问静态。
4.4.6、静态的应用(什么时候使用静态)
当所有对象共享某个数据的时候,就把这个成员变量定义为静态修饰变量;
当某个方法没有访问该类中非静态成员,就把这个方法定义为静态方法。
4.4.7、静态代码块
静态代码块,其实就在代码块前面加上了静态关键字,这个代码块就称为静态代码块。
优先于主方法执行,优先于构造代码块执行,不管创建多少对象,静态代码块只执行一次,可用于给静态变量赋值; 用来给类进行初始化。
public class Person {
private String name;
private int age;
static{
System.out.println("静态代码块执行了");
}
}
静态代码块的应用场景:类不需要创建对象,但需要初始化,这时可以将部分代码存储到静态代码块中
。
普通代码块&构造代码块&局部代码块
普通代码块就是直接定义在方法或语句中定义的代码块。
class Demo{
public static void main(String[] args)
{
{
int x = 1;
System.out.println("普通代码块" + x);
}
int x = 99;
System.out.println("代码块之外" + x);
}
//结果:
//普通代码块1
//代码块之外99
构造代码块:直接写在类中的代码块。优先于构造方法执行,构造代码块用于给所有对象初始化用,每创建一次对象就会执行一次构造代码块。构造函数用于给指定对象初始化。
public class Person {
private String name;
private int age;
static{
System.out.println("静态代码块执行了");
}
{
System.out.println("构造代码块执行了");
}
Person(){
System.out.println("Person无参数的构造函数执行");
}
Person(int age){
this.age = age;
System.out.println("Person(age)参数的构造函数执行");
}
}
class PersonDemo{
public static void main(String[] args)
{
Person p = new Person();
Person p1 = new Person(23);
}
}
代码块里变量的作用域:只在自己所在区域(前后的{})内有效;
局部代码块:写在局部范围内的代码块。作用:就可以控制局部变量的生命周期。
class Demo
{
public static void main(String[] args)
{
{//局部代码块
int x = 5;
System.out.println(" 局部代码块..."+x);
}
System.out.println(" over...");
}
}