Java面向对象总结
面向对象思想概述
概述
Java语言是一种面向对象的程序设计语言,而面向对象思想是一种程序设计思想,我们在面向对象思想的指引下,使用Java语言去设计、开发计算机程序。这里的对象泛指现实中一切事物,每种事物都具备自己的属性和行为。面向对象思想就是在计算机程序设计过程中,参照现实中事物,将事物的属性特征、行为特征抽象出来,描述成计算机事件的设计思想。它区别于面向过程思想,强调的是通过调用对象的行为来实现功能,而不是自己一步一步的去操作实现。
特点
面向对象具有封装、继承、多态、抽象等特性。
类与对象的关系
类是对一类事物的描述,是抽象的。
对象是一类事物的实例,是具体的。
类是对象的模板,对象是类的实体。
成员变量和局部变量
1:在类中的位置不同
成员变量:在类中方法外
局部变量:在方法定义中或者方法声明上
2:在内存中的位置不同
成员变量:在堆内存(成员变量属于对象,对象进堆内存)
局部变量:在栈内存(局部变量属于方法,方法进栈内存)
3:生命周期不同
成员变量:随着对象的创建而存在,随着对象的消失而消失
局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
4:初始化值不同
成员变量:有默认初始化值
局部变量:没有默认初始化值,必须定义,赋值,然后才能使用。
成员变量的默认值
数据类型 | 默认值 | |
---|---|---|
基本类型 | 整数(byte,short,int,long) | 0 |
浮点数(float,double) | 0.0 | |
字符(char) | '\u0000' | |
引用类型 | 布尔(boolean) | false |
数组,类,接口 | null |
案例
1 public class VariableDemo {
2 String name = "成员变量";
3
4 public void show() {
5 String name = "局部变量";
6 System.out.println(name);
7 }
8 public static void main(String[] args) {
9 new VariableDemo().show();
10 }
11 }
输出结果:局部变量
1 public class VariableDemo {
2 String name = "成员变量";
3
4 public void show() {
5 String name = "局部变量";
6 System.out.println(this.name);
7 }
8 public static void main(String[] args) {
9 new VariableDemo().show();
10 }
11 }
输出结果:成员变量
this
(表示调用对象本身)这个关键字用于访问成员变量。
注意事项:局部变量名称可以和成员变量名称一样,在方法中使用的时候,采用的是就近原则。
权限修饰符
Java 中主要有 private、protected、public 和 默认访问权限 四种。
public
修饰符,具有最大的访问权限,可以访问任何一个在 CLASSPATH 下的类、接口、异常等。
protected
修饰符,主要作用就是用来保护子类,子类可以访问这些成员变量和方法,其余类不可以。
default
修饰符,主要是本包的类可以访问。
private
修饰符,访问权限仅限于本类内部,在实际开发过程中,大多数的成员变量和方法都是使用 private 修饰的。
修饰符 | 本类 | 本包 | 外包子类 | 外包 |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | |
default | √ | √ | ||
private | √ |
构造方法
构造方法作用
给对象的数据(属性)进行初始化。
构造方法格式特点
方法名与类名相同(大小也要与类名一致)
没有返回值类型,连void
都没有
没有具体的返回值return;
案例
1 public class ExtendsDemo {
2 public static void main(String[] args) {
3 B aa = new B();
4 System.out.println(aa.num);
5 }
6 }
7
8 class A{
9 int num = 10;
10 public A(int num){
11 this.num = num;
12 }
13
14 public A() {
15 }
16 }
17 class B extends A{
18 public B(){
19 super(5);
20 System.out.println("B构造方法");
21 }
22 }
输出结果:B构造方法
5
说明:
父类有有参构造方法有两种情况,
1.只有有参构造,那么子类的构造方法中的第一句必须调用父类的有参构造方法,也就是“super(....);”,....传入的参数
2.有参也有无参构造方法,这时子类不显示调用super,这会默认自动调用父类无参的构造方法。
总结
- 构造函数是不能继承的,只是用来在子类调用,(如果父类没有无参构造函数,创建子类时,必须在子类构造函数代码体的第一行显式调用父类的有参数构造函数,否则不能编译);
- 如果父类没有有参构造函数,那么在创建子类时可以不显式调用父类构造函数,系统会默认调用父类的无参构造函数
super()
; - 如果父类没有无参构造函数,那系统就调不了默认的无参构造函数了,所以不显示调用编译也就无法通过了;
- 创建有参构造函数后,系统就不在有默认的无参构造函数。
方法重写与方法重载
方法重写Override
子类中出现了和父类中方法声明一模一样的方法。与返回值类型有关,返回值是一致(或者是子父类)的。
方法重载Overload
本类中出现的方法名一样,参数列表不同的方法。与返回值类型无关。
static关键字
static的特点
- 随着类的加载而加载,优先于对象存在。(在静态方法中是没有this关键字的,this是随着对象的创建而存在。)
- 被类的所有对象共享,可以通过类名调用,也可以通过对象名调用,推荐使用类名调用。
静态变量
- 静态变量属于类,所以也称为为类变量,被类的所有对象共享。
- 静态变量存储于方法区的静态区,随着类的加载而加载,随着类的消失而消失。
注意:不能在方法内定义静态变量,因为在方法内定义静态变量根本没有任何意义.任何对象都有自己的方法,即使是静态方法,方法内的变量也是在方法调用时候才开始分配内存。
代码块
代码块概述
在Java中,使用{ }括起来的代码被称为代码块。
代码块分类
根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代码块。
局部代码块 :在方法中出现,限定变量生命周期,及早释放,提高内存利用率。
构造代码块 (初始化块):在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行。
静态代码块:在类中方法外出现,并加上static
修饰;用于给类进行初始化,在加载的时候就执行,并且只执行一次(一般用于加载驱动)。
案例
1 class Student {
2 static {//静态代码块
3 System.out.println("Student 静态代码块");
4 }
5
6 {//构造代码块
7 System.out.println("Student 构造代码块");
8 }
9
10 public Student() {
11 System.out.println("Student 构造方法");
12 }
13 }
14
15 class Demo_Student {
16
17 public static void main(String[] args) {
18 System.out.println("main方法");
19
20 Student s1 = new Student();
21 System.out.println("----------------");
22 Student s2 = new Student();
23 {
24 System.out.println("Demo_Student 局部代码块");
25 }
26 }
27 static {//静态代码块
28 System.out.println("Demo_Student静态代码块");
29 }
30 }
输出结果:
Demo_Student静态代码块
main方法
Student 静态代码块
Student 构造代码块
Student 构造方法
----------------
Student 构造代码块
Student 构造方法
Demo_Student 局部代码块
继承关系代码块
1 public class FuZiDemo {
2 public static void main(String[] args) {
3 Zi z = new Zi();
4 System.out.println("-----------------");
5 Fu c = new Zi();
6 }
7 }
8
9 class Fu {
10 static {
11 System.out.println("静态代码块Fu");
12 }
13
14 {
15 System.out.println("构造代码块Fu");
16 }
17
18 public Fu() {
19 System.out.println("构造方法Fu");
20 }
21 }
22
23 class Zi extends Fu {
24 static {
25 System.out.println("静态代码块Zi");
26 }
27
28 {
29 System.out.println("构造代码块Zi");
30 }
31
32 public Zi() {
33 System.out.println("构造方法Zi");
34 }
35 }
36 /*
37 *输出结果:
38 *
39 静态代码块Fu
40 静态代码块Zi
41 构造代码块Fu
42 构造方法Fu
43 构造代码块Zi
44 构造方法Zi
45 -----------------
46 构造代码块Fu
47 构造方法Fu
48 构造代码块Zi
49 构造方法Zi
50 *
51 * */
多态
多态前提
要有继承关系。
要有方法重写。
要有父类引用指向子类对象。
多态格式
父类类型 变量名 = new 子类类型();
引用类型转换
向上转型:多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。
父类类型 变量名= new 子类类型();如:Animal a = new Cat();
向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。
子类类型变量名=(子类类型)父类变量名;如:Cat c =(Cat)a;
多态特点
成员变量:编译看左边(父类),运行看左边(父类)。
成员方法:编译看左边(父类),运行看右边(子类)。
静态方法:编译看左边(父类),运行看左边(父类)。
(静态和类相关,算不上重写,所以,访问还是左边的,只有非静态的成员方法,编译看左边,运行看右边 )
final关键字
final修饰特点
修饰类,类不能被继承
修饰变量,变量就变成了常量,只能被赋值一次
修饰方法,方法不能被重写
案例
1 public class Staticdemo {
2
3 public static void main(String[] args) {
4 String s1 = "abc";
5 final String s2 = new String("abc");
6 String s3 = "abc";
7 System.out.println(s1 == s2);//false
8 System.out.println(s1 == s3);//true
9 //引用类型有final修饰符也不会进入常量池, 是否进入常量池与final修饰符是没有关系的。
10 System.out.println("--------------------");
11 String a1 = "a";
12 String a2 = a1 +"b";
13 String a3 = "a"+"b";
14 String a4 = "ab";
15 System.out.println(a2 == a4);//false
16 System.out.println(a3 == a4);//true
17 }
18 }
注意:引用类型有final修饰符也不会进入常量池, 是否进入常量池与final修饰符是没有关系的。
抽象类与接口
抽象类定义
没有方法主体的方法称为抽象方法。Java语法规定,包含抽象方法的类就是抽象类。
抽象类:abstract class
类名 {} 抽象方法: public abstract void eat();
注意:
- 抽象类不能实例化,由具体的子类实例化。其实这也是多态的一种,抽象类多态。
- 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。
- 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
- 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
接口概念
接口,是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么接囗的内部主要就是封装了方法,包含抽象方法(JDK7及以前),默认方法和静态方法(JDK8),私有方法JDK9)。
接口使用
它与定义类方式相似,但是使用interface关键字。它也会被编译成.class文件,但一定要明确它并不是类,而是另外一种引用数据类型。它不能创建对象,但是可以被实现(implements
,类似于被继承)。一个实现接口的类(可以看做是接囗的子类),需要实现接口中所有的抽象方法,创建该类对象,就可以调用方法了,否则它必须是一个抽象类。
接口特点
成员变量:只能是常量,并且是静态的并公共的。默认修饰符:public static final
含有抽象方法
抽象方法:使用 abstract 关键字修饰,可以省略,没有方法体。该方法供子类实现使用。
public interface InterFaceName {
void method();
}
含有默认方法和静态方法
默认方法:使用 default 修饰,不可省略,供子类调用或者子类重写。静态方法:使用 static 修饰,供接口直接调用。
public interface InterFaceName {
public default void method() {
//执行语句
}
public static void method() {
//执行语句
}
}
含有私有方法和私有静态方法
私有方法:使用 private
修饰,供接口中的默认方法或者静态方法调用。
public interface InterFaceName {
private void method() {
//执行语句
}
private static void method() {
//执行语句
}
}
匿名内部类
匿名内部类前提
匿名内部类必须继承一个父类或者实现一个父接口。
概念
匿名内部类是内部类的简化写法。它的本质是一个带具体实现的父类或者父接口的匿名的子类对象。
格式
new 父类名或者接口名(){
//方法重写
@override
public void method(){
//执行语句
}
};
类的实例化过程
实例化过程
Student s = new Student();
- JVM 读取指定 classpath 路径下的 class 文件,加载到内存,如果有直接父类,也会加载父类。
- 堆内存分配空间。
- 执行父类静态代码 执行子类静态代码。
- 初始化父类成员变量(我们常说的赋值语句)。
- 初始化父类构造方法(显示初始化)。
- 初始化子类成员变量(我们常说的赋值语句)。
- 初始化子类构造方法(显示初始化)。
- 初始化完毕后,将地址赋值给引用。
案例
1 class Animal {
2 public String name = "Animal";//1.父类初始化赋值
3
4 public Animal() { //2.调用父类构造
5 a();
6 }
7
8 public void a() {
9 System.out.println(name);
10 }
11 }
12
13 class Dog extends Animal {
14 public String name = "Dog"; //3.子类初始化赋值
15
16 public void a() {
17 System.out.println(name);
18 }
19
20 public Dog() { //4.调用子类构造
21 System.out.println(name);
22 }
23
24 }
25
26 public class ExtendsDemo {
27 public static void main(String[] args) {
28 Animal animal = new Dog();
29 }
30 }
输出结果:null
Dog
注意:成员变量按照其声明的顺序会被初始化,这个动作发生在所有事件之前,也就是编译器会立刻将分配给对象的空间初始化。最后就是调用类的构造方法了。