面向对象
- java类的定义方式:类名 对象名 = new 类名();
- 对象也是new出来的,所以存在堆中,其中成员变量的初始化方式跟上面new数组时不同数据类型的默认初始化值是一致的(比如int类型初始化值为0,引用类型的默认初始化值为null,引用类型就比如String)。
- 成员变量和局部变量的区别:
- 在类中的位置不同
- 成员变量:在类中方法外
- 局部变量:在方法定义中或者方法声明上
- 在内存中的位置不同
- 成员变量:在堆内存
- 局部变量:在栈内存
- 生命周期不同
- 成员变量:随着对象的创建而存在,随着对象的消失而消失
- 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
- 初始化值不同
- 成员变量:有默认初始化值
- 局部变量:没有默认初始化值,必须定义,赋值,然后才能使用
- 注意事项:
- 局部变量名称可以和成员变量名称一样,在方法中使用的时候,采用的是就近原则
- 在类中的位置不同
- 匿名对象:就是没有名字的对象。匿名对象的应用场景:
- 调用方法,仅仅只调用一次的时候使用,调用多次时不适合。匿名调用的优点就是调用完成之后对象就可以立即被垃圾回收器回收。
- 匿名对象可以作为实际参数传递。
private
- private关键字是一个权限修饰符。
- 可以修饰成员变量和成员方法,被其修饰的成员只能在本类中才能访问。
- 常用于封装私有属性和私有方法。
构造方法
- 构造方法主要是为了进行对象的初始化,方法名与类名相同。
- 没有返回值类型,甚至没有void。
- 如果没有给出构造方法,系统将自动提供一个无参构造方法。
- 如果给出了构造方法,系统将不再提供。
- 可以进行构造方法的重载,即一个类可以有多个构造方法。
- Student s = new Student();在内存中做了哪些事情?
- 加载Student.class文件进内存
- 在栈内存为s开辟空间
- 在堆内存为学生对象开辟空间
- 对学生对象的成员变量进行默认初始化
- 对学生对象的成员变量进行显示初始化
- 通过构造方法对学生对象的成员变量赋值
- 学生对象初始化完毕,把对象地址赋值给s变量
static
- static关键字可以修饰成员变量和成员方法。
- static关键字特点:随着类的加载而加载、优先于对象存在、被类的所有对象共享、可以通过类名调用。
- static关键字注意事项:在静态方法中是没有this关键字的、静态方法只能访问静态的成员变量和静态的成员方法。
- 静态变量和成员变量的区别:
- 所属不同
- 静态变量属于类,所以也称为为类变量
- 成员变量属于对象,所以也称为实例变量(对象变量)
- 内存中位置不同
- 静态变量存储于方法区的静态区
- 成员变量存储于堆内存
- 生命周期不同
- 静态变量随着类的加载而加载,随着类的消失而消失
- 成员变量随着对象的创建而存在,随着对象的消失而消失
- 调用不同
- 静态变量可以通过类名调用,也可以通过对象调用
- 成员变量只能通过对象名调用
- 所属不同
- 要实现外界不能创建某个类的对象,就要将构造方法私有化,即用private修饰无参构造方法。
代码块
- 局部代码块:局部位置,用于限定变量的生命周期。
- 构造代码块:在类中的成员位置,每次调用构造方法前都会先执行构造代码块。作用:可以把做个构造方法中共同的代码放在一起,对对象进行初始化。
- 静态代码块:在类中成员位置,需要用static进行修饰。作用:一般是对类进行初始化。
- 静态代码块先于构造代码块先于构造方法。
继承
- 实现继承的格式如下:
class 子类名 extends 父类名{
代码块;
}
- java只支持单继承不支持多继承。
- 子类只能继承父类所有非私有的成员(成员方法和成员变量)。
- 子类不能继承父类的构造方法,但是能够通过super访问父类的构造方法。
- 在子类方法中访问一个变量的查找顺序:在该方法的局部变量中查找,如果没有,再在子类的成员变量中查找,如果没有,再在父类的成员变量中查找。也就是就近原则。
- 与this表示本类的引用一样,super表示父类的存储空间标识(可以理解为父类引用,可以操作父类的成员)。super.成员变量 表示调用父类的成员变量;super.成员方法 表示调用父类的成员方法;super(…) 表示调用父类的构造方法。
- 子类中的所有构造方法默认都会访问父类中的空参数构造方法。因为子类构造方法的第一句默认会加上super()。但是,如果在子类的构造方法第一句显式地调用了父类的带参构造方法,那么默认的super()就不会加上。
public class HelloWorld {
public static void main(String [] args){
Son s1 = new Son();
Son s2 = new Son("hello");
}
}
class Father{
public Father(){
System.out.println("父类无参构造方法");
}
public Father(String s){
System.out.println("父类有参构造方法");
}
}
class Son extends Father{
public Son(){
super("hi");//显式调用父类的带参构造方法
System.out.println("子类无参构造方法");
}
public Son(String s){
System.out.println("子类有参构造方法");
}
}
打印结果如下:
父类有参构造方法
子类无参构造方法
父类无参构造方法
子类有参构造方法
- 存在继承关系时,程序的执行方式:
- 首先加载父类,执行父类静态代码块,再加载子类,执行子类静态代码块。
- 加载完成之后进行初始化过程。首先进行父类初始化,再进行子类初始化。
- 对类进行初始化时,对成员变量进行初始化。首先进行默认初始化,然后进行显式初始化,最后进行构造函数初始化。
- 这里有一点需要注意:虽然子类构造方法中默认有一个super(),但初始化的时候,不是按照那个顺序进行的,而是按照分层初始化进行的,即它仅仅表示先要初始化父类数据,再初始化子类数据。看下面这个例子:
class X {
Y b = new Y();
X() {
System.out.print("X");
}
X(String s) {
System.out.print("--X有参--");
}
}
class Y {
Y() {
System.out.print("Y");
}
}
public class Z extends X {
Y y = new Y();
Z() {
// super();//这句话默认存在,但仅仅表示要首先进行父类的初始化而已
// super("hi");//如果将这句话的注释去掉,执行结果将会是:Y--X有参--YZ,说明依然是表示首先要进行父类初始化而已,与上面有所不同的是执行父类初始化时调用的是有参构造函数
System.out.print("Z");
}
public static void main(String[] args) {
new Z();
}
}
运行结果如下:
YXYZ
- 子类中出现与父类中一模一样的方法(包括方法名,返回值类型,参数列表),称为方法重写。子类重写了父类的方法,通过子类调用该方法时,访问的就是子类的方法。注意重写与重载的区别:重载是指同一个类中的方法,方法名相同,参数列表不同。
- 方法重写的应用在于子类可以通过在重写的方法中调用父类的该方法,实现功能的扩展。
- 方法重写的注意事项:
- 父类中的私有方法不能被重写。
- 子类重写父类方法时,访问权限不能更低。
- 父类静态方法,子类也必须通过静态方法进行重写(其实这种情况不是方法重写)。
final
- final关键字表示最终的意思。被final修饰的类不能被继承;被final修饰的变量就成了常量,只能被赋值一次;被final修饰的方法不能被重写。
- finally:是异常处理的一部分,用于释放资源。
- finalize():是Object类中的一个方法,用于垃圾回收。
多态
- 多态的前提:
- 要有继承或者实现关系。
- 要有方法重写(不是必须)。
- 要有父类或者父接口引用指向子类对象。
- 多态中的成员访问特点:
- 成员变量:编译看左边,运行看左边
- 成员方法:编译看左边,运行看右边
- 静态方法:编译看左边,运行看左边
- 总结下来就是只有成员方法能够实现动态特性
- 父类引用指向子类对象,可以对父类引用进行强制转换,称为向下转型。
abstract
- 抽象类的特点:
- 抽象类和抽象方法必须用abstract关键字修饰
- 抽象类中不一定有抽象方法,但是有抽象方法的类必须定义为抽象类
- 抽象类不能实例化,因为它不是具体的。抽象类有构造方法,但是不能实例化。构造方法用于子类访问父类数据的初始化
- 抽象类的子类
- 如果不想重写抽象方法,该子类是一个抽象类。
- 重写所有的抽象方法,这个时候子类是一个具体的类。
- 抽象类的成员方法既可以是抽象的,也可以是非抽象的。
- 抽象方法:强制要求子类重写的方法
- 非抽象方法:子类继承的方法,提高代码复用性
- abstract关键字不能与private、final、static关键字一起出现。因为被abstract修饰的方法一定需要被子类重写,而final、private与之矛盾;被static关键字修饰的方法可以通过类名直接调用,而抽象方法没有进行具体实现。
接口
- 接口的定义格式以及类实现接口的格式:
interface 接口名{
}
class 类名 implements 接口名{
}
- 接口中成员的特点:
- 成员变量:只能是常量,并且是静态的。默认修饰符:public static final.
- 接口没有构造方法。
- 接口中的成员方法只能是抽象方法,且具有默认修饰符public abstract。所以在对抽象方法进行具体实现时,也必须加上public关键字。
- JDK8之后,接口中可以有static修饰的方法和default修饰的方法。
- 类与类、类与接口、接口与接口
- 类与类之间只能单继承。
- 类与接口可以单实现,也可以多实现;也可以在继承一个类的同时实现多个接口。
- 接口与接口可以单继承,也可以多继承。
修饰符
- 权限修饰符对成员方法的限定
本类 | 同一个包下(子类和无关类) | 不同包下(子类) | 不同包下(无关类) | |
---|---|---|---|---|
private | ✔ | |||
默认 | ✔ | ✔ | ||
protected | ✔ | ✔ | ✔ | |
public | ✔ | ✔ | ✔ | ✔ |
-
修饰符种类
- 权限修饰符:private,默认的,protected,public
- 状态修饰符:static,final
- 抽象修饰符:abstract
-
类:
-
权限修饰符:默认修饰符,public
-
状态修饰符:final
-
抽象修饰符:abstract
-
用的最多的就是:public
-
-
成员变量:
-
权限修饰符:private,默认的,protected,public
-
状态修饰符:static,final
-
用的最多的就是:private
-
-
构造方法:
-
权限修饰符:private,默认的,protected,public
-
用的最多的就是:public
-
-
成员方法:
-
权限修饰符:private,默认的,protected,public
-
状态修饰符:static,final
-
抽象修饰符:abstract
-
用的最多的就是:public
-
-
除此以外的组合规则:
- 成员变量:public static final
- 成员方法:public static、 public abstract、 public final
内部类
- 内部类按照位置不同分为成员内部类和局部内部类。
- 内部类可以直接访问外部类的成员,包括私有。(如果是局部内部类访问局部变量,需要在局部变量前面加上修饰符final)
- 外部类要访问内部类的成员,必须创建对象。
- 成员内部类创建对象的格式:
Outer.Inner inn = new Outer().new Inner();
- 成员内部类如果被修饰符static修饰,那么创建内部类对象的方式是:
Outer.Inner inn = new Outer.Inner();
- 匿名内部类
- 前提:存在一个类或者接口,这里的类可以是具体类也可以是抽象类
- 格式:new 类名或者接口名(){重写方法};
- 本质:是创建了一个继承了前面类或者实现了前面接口的子类匿名对象
interface Inner {
public abstract void show();
public abstract void show2();
}
class Outer {
public void method() {
Inter i = new Inner() { //多态的体现,因为等号右边的对象是子类对象
public void show() {
System.out.println("show");
}
public void show2() {
System.out.println("show2");
}
};
i.show();
i.show2();
}
}
class InnerClassDemo6 {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
}
}