目录
三、面向对象
1.概述
面向过程与面向对象
面向对象编程特点
面向对象三个基本特征
2.数组
数组定义格式
数组的初始化
动态初始化
静态初始化
数组的内存分配
Java中的内存分配
数组的内存分配
数组的角标
数组的基本操作
二维数组(实际开发几乎不用)
3.类与对象
定义
使用对象
对象的内存分配
使用对象的内存步骤
成员变量,局部变量区别
匿名对象
应用场景
构造方法
构造方法特点
构造方法的重载
构造方法注意事项
给成员变量赋值的方式
4.static关键字
特点
注意事项
静态变量和成员变量区别
开发中的应用
5.代码块
应用场景
6.final关键字
作用
final修饰变量的初始化时机
7.封装
概述
封装原则
private关键字
this关键字
8.继承
继承的好处和弊端
Java中类的继承特点
继承的注意事项
this和super的区别和应用
继承中构造方法的关系
继承中构造方法注意事项
方法重写
方法重写的注意事项
方法重载
重写与重载区别
9.多态
多态的前提
多态的成员访问
多态中的向上和向下转型
多态的好处和弊端
三、面向对象
1.概述
面向过程与面向对象
面向过程:第一步买菜,第二步洗菜,第三步做菜,第四步吃
面向对象:找对象(对象进行第一步,第二步,第三步)
面向对象编程特点
可以将复杂的事情简单化
将我们从执行者变成了调用者
面向对象编程就是不断的创建对象,使用对象
面向对象三个基本特征
封装(encapsulation)
继承(inheritance)
多态(polymorphism)
2.数组
数组:存储同一种数据类型多个元素的集合
数组作用:存储同种数据类型的多个值,可以存储基本数据类型,引用数据类型
数组定义格式
数据类型[] 数组名 = new 数据类型[数组的长度];
int[] arr = new int[5];
数组的初始化
初始化时,为数组开辟连续的内存空间,并为每个数组元素赋值
动态初始化
只指定长度,由系统给出初始化值(默认值)
数据类型[] 数组名 = new 数据类型[数组长度];
int[] arr = new int[5];
整数类型 byte,short,int,long 默认为0
浮点类型 float,double 默认为0.0
布尔类型 boolean 默认false
字符类型 char 默认为'\u0000' \u是转义字符意为Unicode编码
char是2个字节,16位二进制值,即4位16进制0
在内存中开辟一块连续的空间(地址值赋值给数组变量)
Sop(arr)输出类型和哈希值 [I@... int型一 维数组
int[] arr = new int[5];for (int i = 0; i < arr.length; i++) { //角标从0开始,到arr.length-1System.out.println(arr[i]); //输入出都为0arr[i] = i; //给数组元素赋值
}
静态初始化
给出初始化值,由系统决定长度
初始化的时候,仍然先进行默认初始化(0),然后才进行显式初始化
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,…};
数据类型[] 数组名 = {元素1,元素2,…};
int[] arr = {1,2,3,4,5};for (int i = 0; i < arr.length; i++) {System.out.println(arr[i]);
}
//输出为1,2,3,4,5
数组的内存分配
Java中的内存分配
栈:存储局部变量,方法
堆:存储new出来的数组或对象
方法区
本地方法区:系统相关
寄存器:给CPU使用
数组的内存分配
声明一个数组,会在栈中生成一个数组变量,变量指向堆中new出来的数组实例
当然可以在栈中声明多个数组变量,指向堆中的同一个数组实例
数组的角标
数组元素具有索引角标,从0开始计数,访问不存在的角标时,会报ArrayIndexOutOfBoundsException
数组的基本操作
//遍历
for (int i = 0;i < arr.length ;i++ ) {System.out.print(arr[i] + " ");
}
//查找
for (int i = 0;i < arr.length ;i++ ) {if (arr[i] == value) { return i;}
}
二维数组(不重要,实际开发几乎不用)
格式:
int[][] arr = new int[3][2];
int[][] arr = new int[3][];
int[][] arr = {{1},{2,3},{4,5,6}};
内存分配
栈中声明的二维数组变量,先指向一个一维数组,这个一维数组的每个元素,又分别指向一个一维数组,每个一维数组就是一行
二维数组基本操作
int[][] arr = {{1,2,3},{4,5},{6,7,8,9}};
for (int i = 0;i < arr.length ;i++ ) {//遍历第一层的一维数组 for (int j = 0;j < arr[i].length ;j++ ) {//获取第一层数组元素指向的多个一维数组中的元素System.out.print(arr[i][j] + " ");}System.out.println();
}
3.类与对象
定义
类:java中最基本的单位,是一组相关的属性和行为的集合,理解为一种事物的定义
定义类其实就是定义类的成员(成员变量和成员方法)
属性 就是该事物的描述信息,年龄,性别,即成员变量
功能 就是该事物能够做什么,吃饭,学习,即成员方法
对象:类的实例,举例:类-Person,对象-张三(具体的某个Person)
使用对象
创建对象:类名 对象名 = new 类名();
使用成员变量:对象名.变量名
使用成员方法:对象名.方法名(入参...)
public class Person { //这是一个类,Person类private String name; //对象的成员变量name,ageprivate int age;private int weight = 100;public void sout() {System.out.println(name);System.out.println(age);}
}public static void main(String[] args) {Person zhangSan = new Person(); //这是Person类的一个对象zhangSanzhangSan.sout(); //调用对象的方法
}
//输出null,0,100
//null和0是默认初始化值,100是显式初始化值
对象的内存分配
与数组类似,栈中声明引用型变量,指向堆中new生成的对象,可以多个变量指向同一个对象
使用对象的内存步骤
1.class字节码文件加载进内存方法区,main主方法进栈,Student.class加载
2.栈中声明一个引用型变量,堆中创建对象实例new Student(),进行默认初始化
3.对象属性显式初始化(类成员变量定义时赋值-定义初始化)
4.构造方法进栈,对对象中的属性赋值,构造方法弹栈(构造方法初始化)
5.该对象地址赋给栈中变量,到这一步后,对象就可以使用了
6.调用对象,设置属性,使用功能
7.调用结束,栈中局部变量弹栈,堆中的对象不会消失而是成为垃圾,交由垃圾回收机制处理
成员变量,局部变量区别
在类中的位置不同
成员变量:在类中方法外
局部变量:在方法定义中或者方法声明上
在内存中的位置不同
成员变量:在堆内存(成员变量属于对象,对象进堆内存)
局部变量:在栈内存(局部变量属于方法,方法进栈内存)
生命周期不同
成员变量:随着对象的创建而存在,随着对象的消失而消失
局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
初始化值不同
成员变量:有默认初始化值
局部变量:没有默认初始化值,必须定义,赋值,然后才能使用
注意事项:
局部变量名称可以和成员变量名称一样,在方法中使用的时候,采用的是就近原则
基本数据类型变量包括哪些:byte,short,int,long,float,double,boolean,char
引用数据类型变量包括哪些:数组,类,接口,枚举
方法形参为类名,调用时需要传入该类的对象public void print(Student s){}//print(new Student());
匿名对象
匿名对象定义:没有名字的对象
应用场景
调用方法,仅仅只调用一次的时候,可以简化代码new Person().sout();
作为实际参数传递teacher.work(new Student());
构造方法
构造方法作用:给对象的数据(属性)进行初始化
构造方法特点
方法名与类名相同(大小也要与类名一致)
没有返回值类型,连void都没有,但有权限修饰符
没有具体的返回值return;
构造方法的重载
方法名相同,与返回值类型无关(构造方法没有返回值),只看参数列表
构造方法注意事项
如果我们没有给出构造方法,系统将自动提供一个无参构造方法
如果我们给出了构造方法,系统将不再提供默认的无参构造方法
这个时候,如果我们还想使用无参构造方法,就必须自己给出,实际开发中,很少使用有参构造方法,一般都是通过get,set方法操作成员
class Person {public Person(String n,int a) { //构造方法name = n; age = a;}private string name;private int age;
}static void main(String[] args){Person p = new Person("张三",14);//此时无法使用new Person()无参构造方法
}
给成员变量赋值的方式
显式初始化:定义成员变量时进行赋值
构造方法:给对象中属性进行初始化(new的时候还是会进行默认初始化)
setXxx()方法:通过类提供的public方法修改成员变量的值
4.static关键字
特点
随着类的加载而加载(随着class文件加载进内存)
优先于对象存在(随着class文件加载进内存)
被类的所有对象共享,即所有类都可以使用它
可以通过类名调用,也可以通过对象名调用,推荐使用类名调用
注意事项
静态方法中是没有this关键字的:静态是随着类的加载而加载,this是随着对象的创建而存在,静态比对象先存在
静态方法只能访问静态的成员变量和静态的成员方法
静态变量和成员变量区别
所属不同
静态变量属于类,所以也称为为类变量
成员变量属于对象,所以也称为实例变量(对象变量)
内存中位置不同
静态变量存储于方法区的静态区
成员变量存储于堆内存
内存出现时间不同
静态变量随着类的加载而加载,随着类的消失而消失
成员变量随着对象的创建而存在,随着对象的消失而消失
调用不同
静态变量可以通过类名调用,也可以通过对象调用
成员变量只能通过对 象名调用
开发中的应用
工具类中的方法定义为静态方法,供所有类直接通过类名调用
public class Person {public static void alive() {System.out.println("活着");}
}public static void main(String[] args) {Person.alive();
}
5.代码块
代码块:使用{}括起来的代码被称为代码块
代码块分类:局部代码块,构造代码块,静态代码块,同步代码块
应用场景
局部代码块:在方法中出现;限定变量生命周期,及早释放,提高内存利用率
构造代码块 (初始化块):在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行
静态代码块:在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且只执行一次,一般用于加载驱动
public class Person {static {//静态代码块}{//构造代码块}public static void alive() {System.out.println("活着");}
}
6.final关键字
作用
修饰类,类不能被继承
修饰变量,变量就变成了常量,只能被赋值一次,加载进常量池,而不随方法弹栈
基本类型,是值不能被改变
引用类型,是地址值不能被改变,对象中的属性可以改变
修饰方法,方法不能被重写
final修饰变量的初始化时机
显式初始化 :使用final修饰,显式初始化
构造方法:在构造方法中进行初始化
public class Person {public static final String NAME = "zhangsan";
}
7.封装
概述
封装是指隐藏对象的属性和实现细节,仅对外提供公共访问方式
封装好处:提高了代码的复用性,安全性
封装原则
将不需要对外提供的内容都隐藏起来
把属性隐藏,提供公共方法对其访问
private关键字
是一个权限修饰符,是封装的一种体现形式
可以修饰成员变量和成员方法
被其修饰的成员只能在本类中被访问
this关键字
this关键字作用:代表当前对象的引用
this的应用场景:用来区分成员变量和局部变量重名
public class Person {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;//this.name指的就是当前对象的name属性,将入参name赋值给当前对象的name}
}
8.继承
继承的好处和弊端
好处
提高了代码的复用性
提高了代码的维护性
让类与类之间产生了关系,是多态的前提
弊端
类的耦合性增强了,开发的原则:高内聚,低耦合
耦合:类与类的关系
内聚:就是自己完成某件事情的能力
Java中类的继承特点
Java只支持单继承,不支持多继承。(一个儿子只能有一个爹),可以通过内部类变相的实现多继承
Java支持多层继承(继承体系)
继承的注意事项
子类只能继承父类所有非私有的成员(成员方法和成员变量),对于私有的成员,可以通过公有的功能去访问
子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。
不要为了部分功能而去继承,体现的应该是一种关系,"is a"
继承中的同名变量遵循就近原则,子类为准,实际上在开发中不会出现这样的情况,因为父类已有,子类重新定义没有什么意义
public class Person {public void sout() {System.out.println("我要输出!");}
}
public class Student extends Person { //继承public void sout() { //重写super.sout(); //super是父类对象的引用,调用的是父类的成员System.out.println("我也要自己输出!");}
}
this和super的区别和应用
定义区别
this:代表当前对象的引用,谁来调用我,我就代表谁
super:代表当前对象父类的引用
使用区别
调用成员变量
this.成员变量 调用本类的成员变量,也可以调用父类的成员变量
super.成员变量 调用父类的成员变量
调用构造方法
this(...) 调用本类的构造方法
super(...) 调用父类的构造方法
调用成员方法
this.成员方法 调用本类的成员方法,也可以调用父类的方法
super.成员方法 调用父类的成员方法
继承中构造方法的关系
子类中所有的构造方法默认都会访问父类中空参数的构造方法
因为子类会继承父类中的数据,可能还会使用父类的数据,所以子类初始化之前,一定要先完成父类数据的初始化
其实每一个构造方法的第一条语句默认都是:super()
继承中构造方法注意事项
父类没有无参构造方法,子类怎么办
手写super(参数)
在本类无参构造中使用this(参数)调用本类有参构造,在本类有参构造中使用super(参数)
super(…)或者this(….)必须出现在构造方法的第一条语句上
继承中同名方法遵循就近原则,可以用super.方法名调用父类成员方法
方法重写
重写:子父类出现了一模一样的方法(注意:返回值类型可以是子父类,这个我们学完面向对象讲)
方法重写的应用:当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。这样,即沿袭了父类的功能,又定义了子类特有的内容
方法重写的注意事项
父类中私有方法不能被重写,因为父类私有方法子类根本就无法继承
子类重写父类方法时,访问权限不能更低,如果降低访问权限,会影响多态,最好就是保持一致
父类静态方法,子类也必须通过静态方法进行重写,其实这个算不上方法重写,但是现象确实如此(静态只能覆盖静态)
子类重写父类方法的时候,最好声明一模一样
子类对象调用方法的时候,先找子类本身,再找父类
方法重载
重载:本类中出现的方法名一样,参数列表不同的方法,与返回值类型无关
重写与重载区别
返回值
重载:可以改变返回值类型,只看参数列表,与返回值无关
重写:不可以改变返回值类型(或者是子父类关系),与返回值有关
参数列表
重载:参数列表不同
重写:参数列表相同
9.多态
多态的前提
要有继承关系,要有方法重写,父类引用指向子类对象
public class Person {public void sout() {System.out.println("我要输出!");}
}public class Student extends Person {public void sout() {super.sout();System.out.println("我也要自己输出!");}
}public class Teacher extends Person {public void sout() {System.out.println("i'm teacher,我更要输出!");}
}public static void main(String[] args) {Person zhangsan = new Student();Person lisi = new Teacher();zhangsan.sout();lisi.sout();
}//zhangsan,lisi都是Person,但是执行sout的结果却不一样,这就是多态
//显然,要实现这样的操作,要满足三个条件:继承,重写,父类引用型变量指向子类对象
多态的成员访问
一般的成员,编译时,只看父类有没有该成员,运行时,先看子类有没有该成员
static成员,编译和运行时都只看父类(其实静态成员方法,自己是自己的,不是重写,所以我们可以说,子类无法重写父类的静态方法)
要理解这里就一定要理解继承,子类并不是把父类的非私有成员直接复制为自己的成员,子父类应当看作两个有交集的集合,父类的引用只能指向自己的成员变量,子类引用也只能指向自己的成员变量
多态中的向上和向下转型
肯定是先有向上才有向下,因为子类特有的部分不能无中生有
Person p = new Teacher();//向上
Teacher sp = (Teacher)p;//向下
多态的好处和弊端
弊端:不能使用子类特有的属性和行为,向下转型以后才能使用
好处:
提高代码的维护性(继承体现)
提高代码的扩展性(多态体现),对于某个方法,可以通过父类对象参数,接收所有子类对象(扩展性强),但该对象只能使用父类的成员