JAVA学习记录 面向对象
JAVA类和类的对象
面向对象的两个要素:
-
类:对一类事物的描述,是抽象的、概念上的定义
-
对象:是实际存在的该类事物的每个个体,因此也称为实例(instance)
面向对象程序设计的重点是类的设计
设计类,就是设计类的成员
子类对象实例化过程
- 从结果上来看:(继承性)
子类继承父类以后,就获得了父类中声明的属性或方法
创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。 - 从过程上来看:
当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,直到调用了java.lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中又父类中的结构,子类对象才可以考虑进行调用。
明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建了一个对象,即为new的子类对象。
属性和方法
属性:对应类中的成员变量
属性 = 成员变量 = field = 域 = 字段
创建类的对象 = 类的实例化 = 实例化类
public class PersonTest {
public static void main(String[] args){
//创建Person类的对象
Person p1 = new Person();
//调用对象的属性:对象.属性
p1.name = "Barry";
p1.isMale = true;
System.out.println(p1.name);
//调用对象的方法:对象.方法
p1.eat();
p1.talk("中文");
}
}
//创建类
class Person{
//创建类的属性
String name;
int age = 1;
boolean isMale;
//创建类的方法
public void eat() {
System.out.println("我正在吃饭");
}
public void talk(String language) {
System.out.println("我在使用" + language + "交流");
}
}
面试题:final、finally、finalize的区别?
Object类的使用
- Object类是所有Java类的根父类
- 如果在类中未使用extends关键字指明其父类,则默认父类未java.lang.Object类
- Object类中的功能(属性、方法)具有通用性
- Object类只声明了一个空参构造器
Object类中的方法
equals()方法的使用
面试题:==和equals()的区别
一:==的使用
==运算符
- 可以使用在基本数据类型和引用数据类型变量中
- 如果比较的是基本数据类型变量,比较两个变量保存的数据是否相等,不一定类型要相同
- 如果比较的是引用数据类型变量,比较两个对象的地址值是否相同,即两个引用是否指向同一个对象
二:equals()方法的使用
1.是一个方法,而非运算符
2.只能用于引用数据类型
3.Object类中的equals()的定义:
public boolean equals(Object obj){
return(this == obj);
}
说明:
Object类中定义的equals()和==的作用相同,较两个对象的地址值是否相同,即两个引用是否指向同一个对象
4. 像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。
5.equals()的重写:通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们就需要对Object类中的equals()进行重写
手动实现equals()的重写(有漏洞):
//重写的是Customer类的equals()
//"实体内容"包括age和name
@Override
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(obj instanceof Customer){
Customer cust = (Customer)obj;
//比较两个对象的每个属性是否相同
if(this.age == cust.age && this.name.equals(cust.name)){
return true;
}else{
return false;
}
}else{
return false;
}
}
可以使用Source中的功能自动实现重写equals()
toString()方法的使用
- 当我们输出一个对象的引用时,实际上就是调用当前对象的toString()方法。
- Object类中toString()的定义:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
- 像String、Date、File、包装类等都重写了Object类中的toString方法。使得在调用对象的toString()时,返回"实体内容"信息。
- 自定义类也可以重写toString()方法,当调用此方法时,返回"实体内容"信息。
手动实现:
@override
public String toString(){
return "实体内容";
}
可以使用Source中的功能自动实现重写toString()
方法
方法:对应类中的成员方法
类中方法的声明和使用:
public class Customer {
String name;
int age;
boolean isMale;
//方法:
//void 没有返回值 其他类型有返回值
//可以携带形参也可以不携带形参
public void eat() {
System.out.println("客户在吃饭");
}
public void sleep(int hour) {
System.out.println("客户休息了" + hour + "个小时");
}
public String getName() {
return name;
}
}
注意:
6. 权限修饰符的说明:
默认方法的权限修饰符是public
JAVA规定的四种权限修饰符:privata、public、缺省、protected(在封装性解释)
7. 返回值类型:有返回值的 无返回值的
如果方法有返回值,则必须在方法声明时,指定返回值的类型。同时,方法中需要使用return关键字来返回指定类型的变量或常量。
如果方法没有返回值,使用void来表示。通常,没有返回值的方法中,就不需要使用return。如果使用的话,只能使用 return; 表示结束此方法的意思
8. 方法名:属于标识符,要做到见名知意
9. 形参列表:方法可以声明多个形参,也可以不声明形参,格式:数据类型1 形参1,数据类型2 形参2,…
10. 方法体:方法功能的体现
11. 方法的使用中:可以调用当前类的属性和方法。特殊情况(递归):方法A中又调用了方法A。方法中不能定义方法。
方法的重载(overload): 在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
重载两同一不同:
同一个类,相同方法名,参数列表不同,参数个数不同,参数类型不同
面试题:区分方法的重载和重写
方法的重写
- 重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作。
- 应用:重写以后,当创建子类对象以后,通过子类对象去调用父类中同名同参的方法时,实际执行的是子类重写父类的方法。
- 重写的规定:
方法的声明: 权限修饰符 返回值类型 方法名(形参列表){
//方法体
}
约定俗称:子类中的交重写的方法,父类中的叫被重写的方法
① 子类重写的方法名和形参列表与父类被重写的方法的方法名和形参列表相同
② 子类重写方法的权限修饰符不小于父类被重写的方法的权限修饰符
特殊情况:子类中不能重写父类中声明为private权限的方法
③ 返回值类型:
- 父类被重写的返回值类型是void,则子类重写的方法类型就只能是void
- 父类被重写的返回值是A类型,则子类重写的方法的返回值类型B可以是A类型或者是A类型的子类(如A:Object B:Object/String)
- 父类被重写的返回值是基本数据类型,则子类重写的方法的返回值类型必须是相同的基本数据类型
- 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
- 子类和父类中的同名同参数方法要么都声明成非static的,要么都声明为static的(不是重写)
方法:可变个数的形参
具体使用:
-
格式:数据类型 … 变量名
public void show(String ... strs){ }
-
当调用可变个数形参的方法时,传入的参数个数可以是0、1、2…
-
可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
-
可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载(二者不能共存)
//这两种方法不能共存 public void show(String ... strs){} public void show(String[] args){}
-
可变个数形参在方法的形参中,必须声明在最后一个
-
可变个数形参在方法的形参中,最多只能声明一个可变形参
toString方法
Object类中的toString()的使用:
- 当我们输入一个对象的引用时,实际上就是调用当前对象的toString()
- Object类中toString()的定义:
public String toString(){
return getClass.getName() + “@” + Integer.toHexString(hashCode());
} - 像String、Date、File、包装类等都重写了Object类中的toString()方法
使得在调用对象的toString()时,返回"实体内容"信息 - 自定义类也可以重写toString()方法,当调用此方法时,返回对象的实体内容
main方法的使用说明
- main()方法作为程序的入口
- main()方法也是一个普通的静态方法
- main()方法可以作为我们与控制台交互的方式。(之前使用Scanner)run as - configuration - 选中文件 在Argument中填写参数,以空格隔开
值传递机制
方法的形参传递机制:值传递
-
形参:定义方法时,声明的小括号内的参数
实参:方法调用时,实际传递给形参的数据 -
值传递机制:
如果参数是基础数据类型,此时实参赋给形参的是实参真实存储的数据值。如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值
递归
递归方法:一个方法调用它自身
//递归求和1--n的和
public int getSum(int n){
if(n == 1){
return 1;
}
else{
return n * getSum(n - 1);
}
}
属性赋值的过程
属性赋值的先后属性
- 默认初始化
- 显式初始化
- 构造器中赋值
- 通过"对象.方法"或者"对象.属性"的方式赋值
以上操作的先后顺序:
构造器
构造器(或构造方法、constructor)的使用
一、 构造器的作用:
- 创建对象
- 给对象进行初始化
二、说明:
-
如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
-
定义构造器的格式:权限修饰符 类名(形参列表){ }
-
一个类中定义的多个构造器,彼此构成重载
-
一旦我们显式的定义了类的构造器之后,系统就不在提供默认的空构造器
-
一个类中,至少有一个构造器
//构造器体验 class Person{ //属性 String name; int age; //构造器 public Person(){ System.out.println("Person()......") } //方法 public void eat(){ System.out.println("吃饭") } }
代码块
- 代码块的作用:用来初始化类或者对象
- 代码块如果有修饰的话,只能使用static
- 分类:静态代码块和非静态代码块
- 静态代码块
① 内部可以有输出语句
② 随着类的加载而执行(静态方法时随着类的加载而加载,需要使用"类.静态方法"执行),且只会执行一次
③ 初始化类的信息
④ 静态代码块的执行要优于非静态代码块的执行
⑤ 静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构 - 非静态代码块
① 内部可以有输出语句
② 随着对象的创建而执行
③ 每创建一个对象执行一次
④ 作用:可以在创建对象时,对对象的属性等进行初始化
⑤ 非静态代码块内可以调用静态的属性、静态的方法、非静态的属性、非静态的方法
内部类
-
Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
-
内部类的分类:成员内部类(静态、非静态) VS 局部内部类(方法内、代码块内、构造器内)
-
成员内部类:
① 作为外部类的成员:
---- 调用外部类的结构
---- 可以使用static修饰(外部类不能使用static修饰)
---- 可以被4中不同的权限修饰② 作为一个类:
---- 类内可以定义属性、方法、构造器
---- 可以被final修饰,表示此类不能被继承,不使用final就可以被继承
---- 可以被abstract修饰,表示此类不能不实例化 -
内部类关注的3个问题
① 如何实例化成员内部类的对象
② 如何在成员内部类中去区分调用外部类的结构
③ 开发中局部内部类的使用
①②
class Person{
String name = "Jack";
int age = 10;
public void eat() {
System.out.println("吃饭");
}
//静态成员内部类
static class Dog{
public void show() {
System.out.println("卡拉是一条狗");
}
}
//非静态成员内部类
class Bird{
String name;
public void sing() {
System.out.println("叽叽喳喳");
//调用外部类的非静态属性
Person.this.eat();
}
public void display(String name) {
//没重名的age直接调
System.out.println(age);
//方法的形参
System.out.println(name);
//内部类的属性
System.out.println(this.name);
//外部类的属性
System.out.println(Person.this.name);
}
}
}
成员内部类和局部内部类,在编译以后,都会生成字节码文件
格式:
- 成员内部类:外部类$内部类名.class
- 局部内部类:外部类$数字 内部类名.class
注意点:
在局部内部类的方法中,如果调用局部内部类所声明的方法中的局部变量,要求此局部变量声明为final。
jdk 7 及之前版本,要求此局部变量显式的声明为final的,jdk 8及以后的版本,可以省略final的声明
面向对象的三大特征
封装
一、 封装的作用:隐藏对象内部的复杂性,只对外公开简单的接口。便有外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把该隐藏的隐藏起来,该暴露的暴露出来。
高内聚,低耦合:
- 高内聚:类的内部数据操作细节自己完成,不允许外部干涉
- 低耦合:仅对外暴露少量的方法用于使用
当我们创建一个类的对象以后,我们可以通过“对象.属性”的方式,对对象的属性进行赋值。这里,赋值操作要受属性的数据类型和存储范围的制约。除此之外,没有其他制约条件。但是,在实际问题中,我们往往需要给属性赋值添加额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。同时,我们需要避免用户使用“对象.属性”的方式对属性进行赋值。则需要将属性声明为私有的(private)。此时,针对于属性就体现了封装性。
二、 封装性的体现:
- 将类的属性私有化(private),同时,提供公共(public)的方法(如get和set)来获取和设置此属性。
三、封装性的体现,需要权限修饰符来配合。
- Java规定的四种权限(从小到大排序):private、缺省、protected、public
- 4种权限可以用来修饰类及类的内部结构:属性、方法、构造器、内部类
- 具体的,四种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类;修饰类只能使用:缺省、public。
- 总结封装性:Java提供了4中权限修饰符来修饰类及类的内部结构,体现类与类的内部结构在被调用时的可见性的大小。
继承
1. 继承性的好处
- 减少代码的冗余,提高了代码的复用性
- 便于功能的扩展
- 为之后多态性的使用,提供了前提
继承性的格式
clss A extends B{
}
/*
A:子类、派生类、subclass
B:父类、超类、基类、superclass
*/
2.1 体现:一旦子类A继承父类B以后,子类A就获取了父类B中声明的所有属性和方法。 特别的,父类中声明为private的属性和方法,子类继承父类以后,仍然认为获取了父类中私有的结构。只是因为封装性的影响,使得子类不能直接调用父类的结构而已(使用get方法)。
2.2 子类继承父类以后,还能声明自己特有的属性或方法,实现功能的拓展。子类和父类的关系,不同于子集和集合的关系。
java中继承性的规定
- 一个类可以被多个子类继承
- Java中类的单继承性:一个类只能有一个父类
- 子父类是相对的概念。
- 子类直接继承的父类称为直接父类,间接继承的父类称为间接父类。
- 子类继承父类以后,就获取了直接父类以及所有间接父类的结构。
注意:
- 如果我们没有显式的声明一个类的父类的话,则此类继承于java.lang.Object类。所有java类
- (除java.lang.Object)都直接或间接的继承与java.lang.Object类。
- 所有的java类具有java.lang.Object类声明的功能。
多态
- 理解多态性:可以理解为一个事务的多种形态
- 何为多态性:父类的引用指向子类的对象(子类的对象赋给父类的引用)
- 多态的使用:虚拟方法调用
有了对象的多态性以后,我们在编译器,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。 - 多态性的使用前提:
① 类的继承关系
② 方法的重写 - 对象的多态性,只适用于方法,不适用于属性
/*
父类 Person()
子类 Man()
*/
Person p = new Man();
面试题:多态是编译时行为还是运行时行为?
运行时行为
注意:有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于声明变量为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。
如何才能调用子类特有的属性和方法?
--向下转型:使用强制转换符
/*
Person 父类
Student子类
子类独有方法:study
*/
Person p1 = new Man;//多态
Man m1 = (Man)p1;
m1.study();
instanceof 关键字的使用
- a instanceof A:判断对象a是否是类A的实例。如果是,返回true,如果不是,返回false 。
- 使用情景:为了避免在向下转型时出现ClassCastException的异常,我们在使用向下转型之前先进行instanceof的判断,一旦返回true,就进行向下转型,如果返回false,不能进行向下转型。
- 如果a instanceof A返回true,则a instance B也返回true。其中B是类A的父类
其他关键字
this、super、static、final、avstract、interface、package、import
return关键字的使用:
- 使用范围:使用在方法体中
- 作用:
①. 结束方法
②. 针对于有返回值类型的方法,使用return 数据方法返回所要的数据 - 注意点:return关键字后面不可以声明执行语句
this关键字的使用:
- this可以用来修饰:属性、方法、构造器
- this修饰属性和方法:
this理解为:当前对象或者正在创建的对象
2.1 在类的方法中,我们可以使用“this.属性”或“this.方法”的方式,调用当前对象属性或方法。但是通常情况下我们都选择省略“this.”。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用“this.变量”的方式,表面此变量是属性,而非形参。
2.2 在类的构造器中,我们可以使用“this.属性”或“this.方法”的方式,调用正在创建的对象属性或方法。但是通常情况下我们都选择省略“this.”。特殊情况下,如果方法的形参和类的属性同名时,我们必须显式的使用“this.变量”的方式,表面此变量是属性,而非形参。
package关键字的使用:
- 为了更好的实现项目中类的管理,提出了包的概念
- 使用package声明类或接口所属的包,声明在源文件的首行
- 包,属于标识符,遵循标识符的命名规则、规范、“见名知意”
- 每“.”一次,就代表一层文件目录
补充:同一个包下,不能命名同名的接口、类。不同的报下,可以命名同名的接口、类。
MVC设计模式
MVC是常用的设计模式之一,将整个程序分为三个层次:视图模型层,控制器层与数据模型层。这种将程序输入输出、数据处理,以及数据的展示分离开来的设计模式将程序结构变的灵活而且清晰,同时也描述了程序各个对象间的通信方式,降低了程序的耦合性。
模型层 model 主要处理数据
- 数据对象封装 model.bean/domain
- 数据库操作类 model.dao
- 数据库 model.db
视图层 view 显示数据
- 相关工具栏 view.utils
- 自定义 view.ui
控制层 controller 处理业务逻辑
- 应用界面相关 controller.activity
- 存放fragment controller.fragmment
- 显示列表的适配器 controller.adapter
- 服务器相关的 controller.service
- 抽取的基类 controller.base
单例设计模式
-
类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,在某个类只能存在一个对象实例。
-
如何实现:
① 饿汉式://饿汉式 class Bank{ //1、私有化类的构造器 private Bank() { } //2、内部创建类的对象、要求此对象也必须声明为静态的 private static Bank instance = new Bank(); //3、提供公共的静态方法,返回类的对象 public static Bank getInstance() { return instance; } }
② 懒汉式:
class Order{ //1. 私有化类的构造器 private Order() { } //2. 声明当前类对象,没有初始化 //4. 此对象也必须声明为static的 private static Order instance = null; //3. 声明public、static的返回当前类对象的方法 public static Order getInstance() { if(instance == null) { instance = new Order(); } return instance; } }
③ 区分饿汉式 和懒汉式:
饿汉式:
---- 坏处:对象加载时间过长
---- 好处:饿汉式是线程安全的
懒汉式:
---- 好处:延迟对象的创建
---- 坏处:目前的写法线程不安全 ----->到多线程时修改写法 -
单例模式的优点:由于单例模式只能生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资,如读取配置、产生其他依赖对象时,则可以通过在应用启动时直接产生一个单例对象,然后永久驻留内存的方式来解决。例如:java.lang.Runtime
-
应用场景:网站的计数器、应用程序的日志应用、数据库连接池、项目中读取配置文件的类、Application、windows的任务管理器和回收站
模板方法设计模式
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
解决的问题:
---- 当功能内部一部分实现的确定的,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
---- 在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式。
代理模式
代理模式是Java开发中使用较多的一种设计模式。代理模式就是为其他对象提供一种代理以控制对这个对象的访问。
工厂模式
实现创建者与调用者的分离,即将创建对象的具体过程屏蔽隔离起来,达到提高灵活度的问题。
分类:
-
简单工厂模式,也叫静态工厂模式,就是工厂类一般是使用静态方法,通过接收不同的参数来返回不同的实例对象
缺点:对于增加新产品,不修改代码的话,是无法扩展的。违反了开闭原则(对扩展开放,对修改封闭)。
class XxxFactory{}
-
工厂方法
-
抽象工厂模式
import关键字的使用:
- 在源文件中显式的使用import结构中导入指定包下的类、接口。
- 声明在包的声明和类的声明之间。
- 如果需要导入多个结构,则并列写出。
- 可以使用xxx.*的方式,表示可以导入xxx包下的所有结构。
- 如果使用的类或者结构是java.lang包下定义的,则可以省略import结构。
- 如果使用的类或接口是本包下定义的,则可以省略import结构。
- 如果在源文件中,使用了不同包下的同名的类,则必须至少有一个类需要以全类名的方式显示。
- 使用" xxx.* "的结构可以表面调用xxx包下的所有结构。但是如果使用的是xxx子包下的结构,则仍需要显示导入。
- import static:导入指定类或接口中的静态结构。
super关键字的使用:
14. super关键字理解
15. super可以用来调用:属性、方法、构造器
16. super的使用:
① 我们可以在子类的方法或者构造器中。通过使用"super.属性"或"super.方法"的方式,显式的调用父类中声明的属性或方法。通常情况下,我们习惯省略"super."
② 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须是显式的使用"super.属性"的方式,表明调用的是父类中声明的属性。
③ 特殊情况:当子类中重写了父类的方法,我们要想在子类中调用父类被重写的方法,则必须是显式的使用"super.方法"的方式,表明调用的是父类中被重写的方法
17. super调用构造器:
① 我们可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器
② "super(形参列表)"的使用,必须声明在子类构造器的首行
③ 我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)“只能二选一,不能同时出现
④ 在构造器的首行,没有显式的声明"this(形参列表)“或"super(形参列表)”,则默认调用的是父类中空参的构造器。
⑤ 在类的多个构造器中,至少有一个类的构造器中使用了"super(形参列表)”,调用父类的构造器
static关键字的使用
18. static:静态的
19. static可以用来修饰:属性、方法、代码块、内部类
20. 使用static修饰属性:静态变量(类变量)
① 属性:按是否使用static修饰,又分为:静态属性 vs 动态属性(实例变量)
---- 实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改
---- 静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是已经修改过的。
② static修饰属性的其他说明:
---- 静态变量随着类的加载而加载,可以通过类.静态变量的方式进行调用
---- 静态变量的加载要早于对象的创建
---- 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中
调用 | 类变量(静态变量) | 实例变量 |
---|---|---|
类 | yes | no |
对象 | yes | yes |
- 使用static修饰方法:静态方法
① 随着类的加载而加载,可以通过"类.静态方法"的方式进行调用。
②静态方法中,只能调用静态的方法或属性;非静态方法中,既可以调用静态的方法或属性,也可以调用非晶体方法和属性。
调用 | 静态方法 | 非静态方法 |
---|---|---|
类 | yes | no |
对象 | yes | no |
-
static注意点:
① 在静态的方法中,既不能使用this,也不能使用super。
② 关于静态属性和静态方法的使用,大家都从生命周期的角度去理解。 -
开发中,如何确定一个属性是否要声明为static:
---- 属性时可以被多个对象所共享的,不会随着对象的改变而改变 -
开发中,如何确定一个方法是否要声明为static:
---- 操作静态属性的方法,通常设置为static的
---- 工具类中的方法,习惯上声明为static,例如:Math、Arrays、Collections
final关键字的使用
final:最终的
- final可以用来修饰的结构:类、方法、变量
- final用来修饰一个类:此类不能被其他类继承,例如:String类、System类
- final用来修饰方法:此方法不能被重写
- final用来修饰变量:此时的“变量”就称为一个常量了
①:final修饰属性:可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化
②:final修饰局部变量:尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行从新赋值。
static final 用来修饰属性:全局常量
abstract关键字的使用
-
abstract:抽象的
-
abstract可以用来修饰的结构:类、方法
-
abstract修饰类:抽象类
---- 此类不能实例化
---- 抽象类中一定有构造器,便于子类对象实例化时调用(涉及:子类对象实例化的过程)
---- 开发中,都会提供抽象类的子类,使子类对象实例化,完成相关的操作 -
abstract修饰方法:抽象方法
---- 只有方法的声明,没有方法体
---- 包含抽象方法的类,一定是一个抽象类。反之,抽象类中是可以没有抽象方法的
---- 若子类重写了父类中的所有的抽象方法后,此子类才可以实例化,若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰abstract class Person{ public abstract void eat(); }
-
使用上的注意点:
① abstract不能用来修饰:属性、构造器等结构。但是书写是可以省略不写
② abstract不能用来修饰私有方法、静态方法、final的方法
抽象类的匿名子类:
调试程序
如何调试程序
- System.out.println().
- Eclipse Debug
接口
接口的使用:
-
接口使用interface来定义
-
Java中,接口和类是并列的两个结构
-
如何定义接口:定义接口中的成员
① JDK7及以前:只能定义全局常量和抽象方法
---- 全局常量:public static final的
---- 抽象方法: public abstract的
② JDK8及以后:除了定义全局变量和抽象方法之外,还可以定义静态方法、默认方法… -
接口中不能定义构造器。意味着接口不可以实例化
-
Java开发中,接口都通过让类去实现(implements)的方式来使用。如果实现类覆盖(重写)了接口中的所有抽象方法,则此实现类就可以实例化;如果实现类没有覆盖接口中的所有抽象方法,则此实现类认为一个抽象类。
-
Java可以实现多个接口 ----弥补了Java的单继承性
格式:class AA extends BB implements CC,DD,EE -
接口与接口之间可以继承,而且可以多继承
-
接口的具体使用:体现多态性
-
接口:实际上可以看做是一种规范
面试题:接口类和接口有哪些异同
相同点:不能实例化:都可以包含抽象方法
不同点:
- 把抽象类和接口(jdk7、jdk8、jdk9)的定义、内部结构解释说明
- 类:单继承性 接口:多继承 类与接口:多实现
Java8中接口的新特性
-
接口中可以定义默认方法和静态方法
-
接口中定义的静态方法,只能通过接口来调用
-
通过实现类的对象,可以调用接口中的默认方法。如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法。
-
如果子类(实现类)继承的父类和实现的接口中声明了同名同参数的方法,子类在没有重写此方法的情况下,默认调用的是父类中同名同参数的方法。----类优先原则
-
如果实现类实现了多个接口,而多个接口中定义了同名同参数的默认方法(父类中没有此方法),在实现类没有重写此方法的情况下,会报错。----接口冲突 - 要求必须重写此方法
-
调用接口的方法:
class SubClass extends SuperClass implements CompareA,CompareB{ @Override public void method(){} //父类和接口都有method方法 method();//调用重写的方法 super.method();//调用父类声明的方法 CompareA.super.method();//调用接口A的方法 }
面向接口编程
我们应用程序中,调用的结构都是JDBC中定义的接口,不会出现具体某一个数据库厂商的API。