Java基础知识梳理(二)
面向对象
Java语言是一种面向对象的程序设计语言,而面向对象思想是一种程序设计思想,我们在面向对象思想的指引下,
使用Java语言去设计、开发计算机程序。 这里的对象泛指现实中一切事物,每种事物都具备自己的属性和行为。面向对象思想就是在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,描述成计算机事件的设计思想。 它区别于面向过程思想,强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去操作实现。
面向对象思想是一种更符合我们思考习惯的思想,它可以将复杂的事情简单化,并将我们从执行者变成了指挥者。面向对象的语言中,包含了三大基本特征,即封装、继承和多态。
类和对象
类 :是一组相关属性和行为的集合。可以看成是一类事物的模板,使用事物的属性特征和行为特征来描述该类事物。
- 属性:事物的状态信息。
- 行为:事物能够做什么。
对象 :是一类事物的具体体现。对象是类的一个实例,必然具备该类事物的属性和行为。
类与对象的关系
- 类是对一类事物的描述,是抽象的。
- 对象是一类事物的实例,是具体的。
- 类是对象的模板,对象是类的实体。
成员变量和局部变量
成员变量和局部变量的区别:
public class Car{
String color; //成员变量
public void drive(){
int speed = 80; //局部变量
//……
}
}
成员变量默认值:
基本类型:
整数(byte,short,int,long):0
浮点数(float,double):0.0
字符(char): ‘\u0000’
布尔(boolean):false
引用类型:数组,类,接口 null
局部变量没有默认值,未初始化的局部变量不能使用
在类中的位置不同
- 成员变量:类中,方法外
- 局部变量:方法中或者方法声明上(形式参数)
作用范围不一样
- 成员变量:类中
- 局部变量:方法中
初始化值的不同
- 成员变量:有默认值
- 局部变量:没有默认值。必须先定义,赋值,最后使用
在内存中的位置不同
- 成员变量:堆内存
- 局部变量:栈内存
生命周期不同
- 成员变量:随着对象的创建而存在,随着对象的消失而消失
- 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
对象三大基本特征
1. 封装
封装:即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别;将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,也就是将数据与操作数据的源代码进行有机的结合,形成“类”,其中数据和函数都是类的成员。
封装的步骤:
- 使用 private 关键字来修饰成员变量。
- 对需要访问的成员变量,提供对应的一对 getXxx 方法 、 setXxx 方法。
public,private,protect,default作用域范围
同一个类 | 同一个包 | 不同包的子类 | 不同包的非子类 | |
---|---|---|---|---|
Private | √ | |||
Default | √ | √ | ||
Protected | √ | √ | √ | |
Public | √ | √ | √ | √ |
public: Java语言中访问限制最宽的修饰符,一般称之为“公共的”。被其修饰的类、属性以及方法不仅可以跨类访问,而且允许跨包(package)访问。
private: Java语言中对访问权限限制的最窄的修饰符,一般称之为“私有的”。被其修饰的类、属性以及方法只能被该类的对象访问,其子类不能访问,更不能允许跨包访问。
protect: 介于public 和 private 之间的一种访问修饰符,一般称之为“保护形”。被其修饰的类、属性以及方法只能被类本身的方法及子类访问,即使子类在不同的包中也可以访问。
default:即不加任何访问修饰符,通常称为“默认访问模式“。该模式下,只允许在同一个包中进行访问。
this关键字
this的含义:this代表所在类的当前对象的引用(地址值),即对象自己的引用。方法被哪个对象调用,方法中的this就代表那个对象。即谁在调用,this就代表谁。
构造方法:
当一个对象被创建时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。
构造方法的定义格式:
修饰符 构造方法名(参数列表){
// 方法体
}
- 构造方法的名字必须与定义他的类名完全相同,没有返回类型,甚至连void也没有。
- 如果不提供构造方法,系统会给出无参数构造方法。
- 如果提供了构造方法,系统将不再提供无参数构造方法。
- 构造方法是可以重载的。
重载:
- 1.同一个类
- 2.多个方法的方法名字相同
- 3.参数列表不同/参数个数不同/参数的数据类型不同/不同数据类型的参数顺序不同
重载注意点:
方法的重载和修饰符无关
方法的重载和有无返回值无关
方法的重载和返回值类型无关
方法的重载和参数名无关方法的重载和参数名无关
2,继承
继承 :就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。
Java只支持单继承,不支持多继承。
好处:
提高代码的复用性。
类与类之间产生了关系,是多态的前提。
格式:
通过 extends 关键字,可以声明一个子类继承另外一个父类。
class 父类 {
…
}
class 子类 extends 父类 {
…
}
继承后的特点
成员变量:
子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用 super 关键字,修饰父类成员变量
成员方法:成员方法不重名:对象调用方法时,会先在子类中查找有没有对应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。
成员方法重名:这时被称为重写
重写:
- 1.发生在父类与子类之间
- 2.方法名,参数列表,返回类型(除过子类中方法的返回类型是父类中返回类型的子类)必须相同
- 3.访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
- 4.重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常
构造方法:
- 构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。
- 构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个 super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。
抽象类-abstract
- 在Java语言中使用abstract关键字修饰类,这该类就成了抽象类,抽象类不能被实例化
- 使用 abstract 关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体。我们把没有方法主体的方法称为抽象方法。
抽象的使用:
继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。
抽象类和抽象方法:
有抽象方法的类,一定是抽象类;但是抽象类中可以不是抽象方法;
3,多态
多态 : 是指同一行为,具有多个不同表现形式。
父类类型 变量名 = new 子类对象; //父类类型:指子类对象继承的父类类型,或者实现的父接口类型。
变量名.方法名();
当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写后方法。
重载也是多态的一种体现
引用类型转换
多态的转型分为向上转型与向下转型两种
- 向上转型 :多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。当父类引用指向一个子类对象时,便是向上转型。
格式:
父类类型 变量名 = new 子类类型();
- 向下转型 :父类类型向子类类型向下转换的过程,这个过程是强制的。一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。
格式:
子类类型 变量名 = (子类类型) 父类变量名;
接口
接口的定义,它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并不是类,而是另外一种引用数据类型。
接口的使用,它不能创建对象,但是可以被实现( implements ,类似于被继承)。java只支持单继承,但是可以实现多个接口
定义格式:
public interface 接口名称 {
// 抽象方法
// 默认方法
// 静态方法
// 私有方法
}
类与接口
类与接口的关系为实现关系,即类实现接口,该类可以称为接口的实现类,也可以称为接口的子类。实现的动作类似继承,格式相仿,只是关键字不同,实现使用 implements 关键字。
default关键字
在java8以后,接口中可以添加使用default或者static修饰的方法,在这里我们只讨论default方法,default修饰方法只能在接口中使用,在接口中被default标记的方法为普通方法,可以直接写方法体。
我们知道Java语言中一个类只能继承一个父类,但是一个类可以实现多个接口。随着默认方法 (default)的引入,有可能出现一个类继承了多个签名一样的方法。这种情况下,类会选择使用哪一个函数呢?
为解决这种多继承关系,Java提供了下面三条规则:
1,类中的方法优先级最高,类或父类中声明的方法的优先级高于任何声明为默认方法的优先级。
2,如果第一条无法判断,那么子接口的优先级更高:方法签名相同时,优先选择拥有最具体实现的默认方法的接口, 即如果B继承了A,那么B就比A更加具体。
3,最后,如果还是无法判断,继承了多个接口的类必须通过显式覆盖和调用期望的方法, 显式地选择使用哪一个默认方法的实现。
比如以下代码:
public interface A {
default void hello() {
System.out.println(“Hello from A”);
}
}
public interface B extends A {
default void hello() {
System.out.println(“Hello from B”);
}
}
public class C implements A, B {
public static void main(String[] args) {
// 猜猜打印的是什么?
new C().hello();
}
}
对比3条规则,发现规则(2)符合条件,所以打印的是Hello from B
抽象方法多实现
接口中,有多个抽象方法时,实现类必须重写所有抽象方法。如果抽象方法有重名的,只需要重写一次。
默认方法多实现
接口中,有多个默认方法时,实现类都可继承使用。如果默认方法有重名的,必须重写一次。
静态方法多实现
接口中,存在同名的静态方法并不会冲突,原因是只能通过各自接口名访问静态方法。
优先级的问题
当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的默认方法重名,子类就近选择执行父类的成员方法。
注意事项:
- 子接口重写默认方法时,default关键字可以保留。
- 子类重写默认方法时,default关键字不可以保留。
- 接口中,无法定义成员变量,但是可以定义常量,其值不可以改变,默认使用 public static final修饰。
- 接口中,没有构造方法,不能创建对象。
- 接口中,没有静态代码块。