JAVASE基础-特性
面向对象
对于C语言来说,是完全面向过程的。
对于Java语言来说,是完全面向对象的。
采用面向对象的方式进行开发:耦合度低,扩展力强。
三个术语OOA/OOD/OOP:
① OOA:面向对象分析(Object-Oriented Analysis)
② OOD:面向对象设计(Object-Oriented Design)
③ OOP:面向对象编程(Object-Oriented Programming)
整个软件开发的过程,都是采用OO进行贯穿的。
三大特征
封装,继承,多态。
类和对象
解释:
将现实世界中某些事物具有的共同特征提取出来形成的概念就是一个“类”,实际存在的个体是对象。
定义类的语法格式
[修饰符列表] class 类名 {
//类体 = 属性 + 方法
// 属性在代码上以“变量”的形式存在(描述状态)
// 方法描述动作/行为
}
对象的创建和使用
类是模板,通过一个类,可以创建N多个对象。new是一个运算符,专门负责对象的创建。java中所有的“类”都属于引用数据类型。(类近似C中结构体)
创建对象:
1 | new 类名(); |
使用例:
1 | 文件XueSheng.java: |
应先编译XueSheng.java,再编译XueShengTest.java。但是对于编译器来说,编译XueShengTest.java文件的时候,会自动找XueSheng.class,如果没有,会自动编译XueSheng.java文件,生成XueSheng.class文件。
对象的创建和使用
对象的创建引用
类名 变量名 = new 类名();
但凡是变量,该变量中保存了指向堆内存当中的对象的内存地址。
参数传递
方法调用时参数的传递:复制值传递。(内存也是值)
基本数据类型:传递值
引用数据类型:传递内存地址(类似指针)
引用数据类型例,以下结果均为11:
1 | public class Test2{ |
构造方法Constructor
构造方法是一个比较特殊的方法,通过构造方法可以完成对象的创建,以及实例变量的初始化。
当一个类中没有提供任何构造方法,系统默认提供一个无参数的构造方法。这个无参数的构造方法叫做缺省构造器。
构造方法是支持方法重载的。
实例变量在构造方法中没有手动赋值时,默认赋系统值。建议将无参数构造方法手动的写出来,这样一定不会出问题。
调用构造方法语法格式:
1 | new 构造方法名(实际参数列表); |
构造方法的语法结构:
1 | [修饰符列表] 构造方法名(形式参数列表){ |
注意:
第一:修饰符列表目前统一写:public。千万不要写public static。
第二:构造方法名和类名必须一致。
第三:构造方法不需要指定返回值类型,也不能写void,写上void表示普通方法,就不是构造方法了。
使用例:
1 | public class Vip{ |
封装
一个类体当中的数据封装之后,对于代码的调用人员来说,不需要关心代码的复杂实现,只需要通过一个简单的入口就可以访问了。另外,将类体中安全级别较高的数据封装起来,外部人员不能随意访问,保证数据的安全性。
具体步骤:
第一步:属性私有化(使用private关键字进行修饰。)
第二步:对外提供简单的操作入口。
使用例:
定义Person类Person.java
1 | public class Person{ |
注意:
java开发规范中有要求,set方法和get方法要满足以下格式。
1 | get方法的要求: |
this和static
static
1、static翻译为“静态”
2、所有static关键字修饰的都是类相关的,类级别的。
3、所有static修饰的,都是采用“类名.”的方式访问。
4、static修饰的变量:静态变量
5、static修饰的方法:静态方法
变量的分类:
变量根据声明的位置进行划分:
在方法体中声明的变量叫做:局部变量。
在方法体外声明的变量叫做:成员变量。
成员变量又可以分为:
实例变量
静态变量
1 | class VarTest{ |
变量在内存中的储存位置:
局部变量:栈区
实例变量:堆区
静态变量:方法区
什么时候变量声明为实例的,什么时候声明为静态的?
如果这个类型的所有对象的某个属性值都是一样的,不建议定义为实例变量,浪费(堆区)内存空间。建议定义为类级别特征,定义为静态变量,在方法区中只保留一份,节省内存开销。
访问
实例相关的都需要new对象,使用”引用.”来访问。
静态方法不需要new对象,直接使用“类名.”来访问,但是也可以使用“引用.”来访问,不建议用,易造成维护迷惑。
1 | public class StaticTest04{ |
静态和实例在具体使用场景的选择
与所在的类绑定不更改的使用静态,随new出来的实例变化的使用实例。只有在实例方法中才可以直接访问实例变量。
静态代码块
static静态代码块在类加载时执行。提供类加载时机。并且只执行一次。使用static关键字可以定义静态代码块,语法:
1 | static { |
静态代码块在类加载时执行,并且在main方法执行之前执行。静态代码块和静态变量都在类加载的时候按照自上而下的顺序执行。
实例语句块
Instance实例语句在类加载时不执行,在每次构造方法执行之前,自动执行“实例语句块”中的代码,提供对象构建时机。语法:
1 | { |
this
this是一个关键字,全部小写。this是一个变量,是一个引用。this保存当前对象的内存地址,指向自身。所以,this代表的就是“当前对象”。this存储在堆内存当中对象的内部。静态方法中不存在当前对象,所以this不能使用在静态方法中。“this.”大部分情况下可以省略。
1 | class Student{ |
不能省略“this.”的情况
为了区分局部变量和实例变量时,this. 不能省略。
1 | // 学生类 |
this()
this除了可以使用在实例方法中,还可以用在构造方法中。通过当前的构造方法去调用另一个本类的构造方法以做到代码复用,可以使用以下语法格式:
1 | this(实际参数列表); |
注意:
对于this()的调用只能出现在构造方法的第一行。
使用例:
1 | class Date{ // 代码封装,属性私有化,对外提供setter and getter |
继承(Inheritance)
作用
基本作用:子类继承父类,代码可以得到复用。(理解为节省储存的复制,故不能理解为调用)
主要(重要)作用:有了继承关系,才有了方法覆盖和多态机制。
相关特性
- B类继承A类,则称A类为超类(superclass)、父类、基类,B类则称为子类(subclass)、派生类、扩展类。语法:
1 | class A{} |
- java 中的继承只支持单继承,不支持多继承,C++中支持多继承,换句话说,java 中不允许这样写代码:
1 | class B extends A,C{ } |
java 中不支持多继承,但有的时候会产生间接继承的效果。例如:class C extends B,class B extends A,则C 直接继承 B,间接继承 A。
子类继承父类,除构造方法不能继承之外,剩下都可以继承。但是私有的属性无法在子类中直接访问(父类中private修饰的不能在子类中直接访问。可以通过间接的手段来访问)。
所有类则默认继承 Object类,Object类是 java 语言提供的根类,也就是说,一个对象与生俱来就有 Object类型中所有的特征。
继承也存在缺点,类继承导致耦合度高。
使用条件
属性有交集时可以使用。
方法覆盖和多态(Polymorphism)
方法覆盖
子类继承父类时,当继承的方法无法满足当前子类的需求时,子类有权利对这个方法进行重新编写,叫“方法的覆盖”。
方法覆盖又叫做:方法重写(重新编写),英语:Override、Overwrite。
比较常见的:方法覆盖、方法重写、override
条件
- 两个类必须要有继承关系。
- 重写之后的方法和之前的方法具有:
相同的返回值类型、 相同的方法名、 相同的形式参数列表。
- 访问权限不能更低,可以更高。
- 重写之后的方法不能比之前的方法抛出更多的异常,可以更少。
注意:
- 方法覆盖只是针对于方法,和属性无关。
- 私有方法无法覆盖。
- 构造方法不能被继承,所以构造方法也不能被覆盖。
- 方法覆盖只是针对于“实例方法”,“静态方法覆盖”没有意义。
- 重写之后的方法和之前的方法具有的返回值类型如果是基本数据类型,则必须一致。如果是引用数据类型,重写之后返回值类型可以变的更小(但实际开发中基本不用)。
使用例:覆盖Object类中的toString()方法
1 | public class OverrideTest04{ |
多态
多态表示多种形态:编译的时候一种形态,运行的时候另一种形态。
静态绑定发生在编译阶段,绑定父类的方法。动态绑定发生在运行阶段,动态绑定子类型对象的方法。
向上转型
子 —> 父(自动类型转换)
1 | public class Test01{ |
向下转型
父 —> 子(强制类型转换,需要加强制类型转换符)
什么时候必须使用“向下转型”?
不要随便做强制类型转换。
当你需要访问的是子类对象中“特有”的方法。此时必须进行向下转型。
1 |
|
instanceof:避免向下转型的风险
1 | Animal a6 = new Bird(); //表面上a6是一个Animal,运行的时候实际上是一只鸟儿。 |
避免ClassCastException异常的发生
java规范中要求,对类型进行向下转型时,一定要使用运算符:instanceof (运行阶段动态判断)
- instanceof可以在运行阶段动态判断引用指向的对象的类型。
- instanceof的语法:
1 | 引用 instanceof 类型 |
- instanceof运算符的运算结果只能是:true/false
- c是一个引用,c变量保存了内存地址指向了堆中的对象。
(c instanceof Cat)为true:
(c instanceof Cat)为false:c引用指向的堆内存中的java对象是一个Cat。
c引用指向的堆内存中的java对象不是一个Cat。
1 | System.out.println(a6 instanceof Cat); //false |
以下写在其他文件中:
1 | // 动物类:父类 |
super
特点
super与this有许多共同点。(可理解为特殊的this,作用于子类继承的父类特征)
- super能出现在实例方法和构造方法中。
- super的语法是:“super.”、“super()”
- super不能使用在静态方法中。
- super. 大部分情况下是可以省略的。
- super.什么时候不能省略呢? ???????
- super() 只能出现在构造方法第一行,通过当前的构造方法去调用“父类”中的构造方法,目的是:创建子类对象的时候,先初始化父类型特征。
注意:
super 不是引用。super也不保存内存地址,super也不指向任何对象。super 只是代表当前对象内部的那一块父类型的特征。
使用例:
1 | public class SuperTest06 { |
super()
调用父类的构造方法。当一个构造方法第一行既没有this()又没有super()时,默认存在一个super(),表示通过当前子类的构造方法调用父类的无参数构造方法。所以必须保证父类的无参数构造方法是存在的。
this()和super() 不能共存。
在java语言中不管new什么对象,Object类的无参数构造方法一定会执行。(Object类的无参数构造方法是处于“栈顶部”)
使用例:
1 | //输出顺序:13654 |
注意:
写代码时,应手动写出一个类的无参数构造方法,否则可能会影响到“子类对象的构建”。
super.
访问父类的属性: super.属性名
访问父类的方法: super.方法名(实参)
super. 大部分情况下可以省略。当父类和子类中有同名属性,有同样的方法,想在子类中访问父类的,super. 不能省略。
1 | 访问当前对象的name属性: this.name |
使用例1:访问父类的属性
1 | public class SuperTest05{ |
1 | public void shopping(){ |
使用例2:访问父类的方法
1 | /* 输出: |