面向对象的基础
1.类和对象
- 类:类别,用来区分一类事物
- 如:电脑,汽车,人,动物,等等…
- 每类事物都具有: 属性和行为
- 属性: 就是该事物所具有的特征(成员变量)
- 行为:就是该事物可以做的事(实现的具体功能)
定义类的思路
就是定义一个类的属性和行为
public class Student {
private String name ; // 定义了name属性,并且的私有的
private int age; // 定义了age属性
public void setName(String name) {
this.name = name ;
}
public String getName() {
return name ;
}
public void setAge(int age) {
this.age = age ;
}
public int getAge() {
return age ;
}
// 吃饭
public void show() {
System.out.println() ;
}
}
使用类:
- 格式:类名 对象名 = new 类名();
- 对象:就是某一个事物的具体体现
- 类和对象的关系:一对多
- 万物皆对象
//创建对象
Student s1 = new Student() ;
Student s2 = new Student() ;
...
// 调用方法
s1.show();
s2.show();
- 什么是面向对象?
- 面向对象:指挥对象去做事,不考虑怎么做,只负责指挥
- 代码的体现:创建对象并调用方法,不考虑功能是如何实现的,只负责调用
- 方法的调用:方法需要什么参数就传什么参数,方法的返回值类型是什么,就用什么类型的变量来接收
Student s1 = new Student() ;
// public int getNumber(int number)
int number = s1.getNumber(12) ;
2.对象内存
2.1 一个对象的内存图
JVM(java虚拟机)的内存结构:
- 栈(java虚拟机栈):每调用一个方法时,都需要将方法加载到栈内存中
- 局部变量:在方法上或者方法内声明(定义)的变量,随着方法的入栈而创建,随着方法的出栈而消失
- 堆(java虚拟机堆):所有通过new关键字所创建的东西
- 方法区:存储某一各类的字节码(.class)文件
- 本地方法栈:主要是用来执行本地方法
- 本地方法:被native关键字修饰的方法就是本地方法
- 如:Object类中的hashCode方法就是一个本地方法,执行时,需要把这个方法加载到本地方法栈中,该方法是去调用c语言中的代码
- 程序计数器:存储的是执行程序的行号
- 为什么要把程序的行号存储到程序计数器中呢?
- 程序的多线程
- 为什么要把程序的行号存储到程序计数器中呢?
类的加载时机:当使用到某一各类的时候,才会把这个类加载到内存
public class Student {
...
}
public class StudentDemo {
public static void main(String[] args) {
Student s1 = new Student() ;
}
}
/*
先把StudentDemo这个类的字节码文件加载到方法区,然后把main方法加载在栈内存,然后在把Student的字节码文件加载到方法区。
*/
2.2两个对象的内存图
- 每new一次都会在堆内存中开辟一个新的内存空间
- 方法中的this是谁?
- 谁调用的方法,方法的this就是指谁
2.3两个引用变量指向同一个内存空间
Student s1 = new Student();
s1.setName("张三");
Student s2 = s1;
s2.setName("李四");
s1.show();//李四---0
s2.show();//李四---0
/*
上述代码创建了1个对象,只不过这个对象有两个名字: s1 , s2
而s1和s2存储的都是同一个对象的地址值。
*/
多个引用变量指向同一个内存空间,不管是通过哪一个引用变量去操作,这个内存空间内的数据都会发生改变.
也就是说,引用变量所存储的是这篇内存空间的地址,当调用时,是获取这个空间的内存地址,从而进行操作
3 static关键字
3.1 static关键字的特点
static关键字翻译成中文是"静态"的意思,我们可以使用static来修饰成员变量,也可以使用static来修饰成员方法,被static修饰的成员变量,我们常常称之为类变量,被static修饰的成员方法我们常常称之为类方法
特点:
- 被该类的所有对象所共享
- 可以通过类名直接访问
//访问成员变量,并且这个成员变量没有被private所修饰
类名.变量名 = 具体的值;
//访问成员方法,并且这个成员方法没有被private所修饰
//没有返回值
类名.方法名(实际参数)
//有返回值
数据类型 变量名 = 类名.方法名(实际参数)
ps: 可以简化方法的调用,不用再创建对象.
是否需要把所有的方法都用static修饰呢?
不行,因为static修饰的成员生命周期(存在的时间)比较长,内存的占用时间也就越长
- 随着类的加载而加载,消失而消失
3.2 static修饰的成员内存图
- 被static修饰的成员是储存于静态区的
静态区
1.7以前:静态区是属于方法区内的
1.8以后:静态区被移到堆内存中
3.3 static关键字注意事项
静态只能访问静态,非静态可以访问静态也可以访问非静态,并且在静态方法中不能存在this关键字
3.4 静态的使用场景
static可以修饰成员变量: 看这个成员变量是否需要被该类的所有对象所共享
static可以修饰成员方法:为了方便进行访问的调用可以直接使用static进行修饰,一般情况下体现在工具类中
public class ArrayUtils {
// 遍历数组
public static void print(int[] arr) {
System.out.print("[");
for(int x = 0 ; x < arr.length ; x++) {
if(x == arr.length - 1) {
System.out.print(arr[x]);
}else {
System.out.print(arr[x] + ", ");
}
}
System.out.print("]");
}
}
4 面向对象的三大特征
4.1 封装
- 封装:就是一个东西把另外一部分的东西包裹起来
- 现实生活中的封装: 电脑,插座,等等…
- 程序的封装:
/*
1.方法
2.类
*/
- 封装的好处:
- 提高了代码的复用性
- 提高了代码的维护性
- 提高了代码的安全性
- 常见封装的使用:把方法所需要的的多个参数使用一个对象来进行封装,后期直接把参数传给对象即可
public void regist(String name , int age , String address , String phone ) {
...
}
public void regist(Student s) {
...
}
// 使用对象去封装方法的参数
Student s1 = new Student() ;
s1.setName("itcast") ;
s1.setAge(16) ;
s1.setAddress("北京") ;
s1.setPhone("6287638721") ;
// 调用方法
regist(s1);
4.2 继承
- 继承:类与类的一种关系
- 格式
public class 子类 extends 父类 {
}
public class B {
public void show() {
System.out.println("B....show...........") ;
}
}
public class A extends B { // A继承B,A常常将其称之为子类,B常常将其称之为父类
}
- 特点:子类可以使用父类中的非私有成员
- 好处:
- 提高了代码的复用性
- 提高了代码的维护性
- 是多态的前提
在整个继承体系中,顶层定义的都是这个继承体系的共性的内容,而底层定义的则是该体系中特有的内容
在java语言中,类和类之间只能是单继承,但可以使多层继承
4.3 多态
- 多态: 同一个行为的不同体现方式
- 前提
- 需要存在继承或者实现的关系
- 需要有方法的重写
- 父类引用指向子类对象
- 多态中的成员访问特点
- 成员方法(非静态):编译看左边,执行看右边
- 成员变量:编译看左边,执行看左边
- 好处:提高了程序的灵活性
public class PersonDemo01 {
public static void main(String[] args) {
// 创建学生对象
Student s1 = new Student() ;
usePerson(s1);
// 创建老师对象
Teacher t1 = new Teacher() ;
usePerson(t1);
System.out.println("---------------------------------");
// 使用多态的方式进行方法的调用
Person p1 = new Student() ;
p1.study();
Person p2 = new Teacher() ;
p2.study();
}
// 定义方法的参数为父类类型
public static void usePerson(Person p) { // Person p = new Teacher() ;
p.study();
}
}
4.4抽象类
- 抽象方法:当我们在定义一个方法时,如果我们不能确定这个方法的方法体内容,此时就可以把该方法定义成抽象方法
public abstract 返回值类型 方法名(参数列表) ;
- 抽象类:当某个类中出现抽象方法,name这个类就需要定义成抽象类
public abstract class 类名 {}
- 抽象类的注意事项
- 抽象类不能实例化(就是不能直接创建对象)
- 有构造方法
- 抽象类中不一定有抽象方法,但有抽象方法的一定是抽象类
- 子类可以是抽象类,也可以是具体类(具体类需要重写所有的抽象方法)
- 使用场景: 模板设计模式
- 设计模式:设计模式是一套被反复使用的,多数人知晓的,经过分类编目的,代码设计经验的总结
- 设计模式:就是一种代码书写的规范,一种套路
- 使用设计模式的好处: 提高了代码的维护性
- 在java中一共有23种设计模式
- 模板设计模式:是一种常见的设计模式,它阐述的思想是:把抽象类整体就可以看成一个模板,模板中不能决定的东西定义成抽象方法,让使用模板的实现类取重写抽象方法实现需求
- 模板是将一个事物的结构规律予以固定化,标准化的成果,它体现的是结构形式的标准化
// 写作文的模板类
public abstract class CompositionTemplate {
// 模板方法:定义了代码结构的方法,我们可以将其称之为模板方法
public void write() {
// 标题
System.out.println("<<我的爸爸>>");
// 作文的正文
body();
// 结束语
System.out.println("啊, 这就是我的爸爸....");
}
// 作文的正文的抽象方法
public abstract void body();
}
public class TomCompositionTemplate extends CompositionTemplate {
@Override
public void body() {
System.out.println("我把爸爸的区长.........");
}
}
public class JackCompositionTemplate extends CompositionTemplate{
@Override
public void body() {
System.out.println("我的爸爸是李刚.......");
}
}
4.5 接口
- 接口:当某一个类的方法都是抽象方法时,此时就可以定义成一个接口,接口其实就是去定义一些规则
public interface 接口名 {
// 定义抽象方法
}
- 特点
- 接口中的成员变量是默认存在修饰符public static final的
- 接口中没有构造方法
- 接口中的方法都是抽象方法(JDK1.7以前)
- 类和接口之间的关系是实现的关系,可以单实现也可以多实现
- 接口和接口之间的关系是继承关系,并且可以多继承
public class 类名 implements 接口1 , 接口2 , .... { }
- 适配器的设计模式
public interface Inter {
public abstract void aaa() ;
public abstract void bbb() ;
public abstract void ccc() ;
public abstract void ddd() ;
public abstract void eee() ;
public abstract void fff() ;
}
public class InterAdaper implements Inter { // 适配器类
@Override
public void aaa() {
}
@Override
public void bbb() {
}
@Override
public void ccc() {
}
@Override
public void ddd() {
}
@Override
public void eee() {
}
@Override
public void fff() {
}
}
public class MyInter extends InterAdaper { // 子类
@Override
public void aaa() {
System.out.println("MyInter.....aaaaa...");
}
}
public class MyInter2 extends InterAdaper { // 子类
@Override
public void ccc() {
System.out.println("MyInter2........cccc....");
}
}
5 接口中的新特性
5.1 默认方法
- 概述:JDK1.8以后允许在接口中去定义非抽象方法,但是这个方法不许通过default关键字来修饰,那么这个方法就是默认方法
- 解决的问题:接口的升级
public default 返回类型 方法名(参数列表) {}
public default void show() {
System.out.println("default....show...method..........") ;
}
- 注意事项:
- 子类可以不必重写这个默认方法,但如果需要重写,就需要去掉default关键字
- 默认方法的public关键字可以省略,但defafault不能省略
- 如果一个实现类实现了多个接口,那么这个类就必须重写重名的默认方法
public interface Inter1 {
public default void show(){
System.out.println("Inter1....show......") ;
}
}
public interface Inter2 {
public default void show(){
System.out.println("Inter2....show......") ;
}
}
public class InterImpl implements Inter1 , Inter2 {
public void show(){
System.out.println("InterImpl....show......") ;
}
}
InterImpl interImpl = new InterImpl();
interImpl.show();
5.2 静态方法
public static 返回值类型 方法名(参数列表) {}
public static void show() {
System.out.println("static....show....") ;
}
- 注意事项
- 静态方法只能通过接口名进行调用
- public关键字可以省略,但static不能省略
5.3 私有方法
private static 返回值类型 方法名(参数列表) {}
private 返回值类型 方法名(参数列表) {}
private static void show() {
System.out.println("static....show....") ;
}
private void method() {
System.out.println("method....show....") ;
}
- 常见的使用场景:就是把接口中默认的方法或者静态的方法中重复的代码抽取出来,定义在私有方法中
- 注意事项:只能在本接口中使用