java入门第三节
一.什么是oop
1.pop与oop
(1).面向过程编程:(POP:Procedure Oriented Programming)
1.步骤清晰简单,第一步做什么,第二步做什么,按照顺序;
2.代码线性,严格按着顺序,侧重解决步骤
3.适合处理一些简单的问题
(2).面向对象编程:(OOP:Object Oriented Programming)
1.物以类聚,分类的思维方式,首先站在更高的层次看待事物,解决那些问题需要分类,然后对这些分类进行单独思考并规划和设计,最后才对某个分类下的细节进行面向过程的思考;(如.制定学习计划,先分科目,如英语,数学,再对每个科目怎么学进行思考,最后按计划依次执行)
2.明确目标,对象就是目标,目标就是对象
3.面向对象适合处理一些复杂的问题,适合处理多人协作的问题;(如.学校里面有很多老师,每个老师教的课程是不一样的,所有进行了分类,协作教育学生)
2.关于OOP的一些基本概念
(1).面向对象编程的本质:以类的方式组织代码,以对象的组织(封装)数据;
(2).三大特性:封装,继承,多态
(3).从认识论角度考虑是先有对象后有类。对象,是具体的事物(如.人)。类,是抽象的,是对对象的抽象(如.一个组织);
(4).从代码运行角度考虑是先有类后有对象,类是对象的模板;(如.印钞必须先有钞票的模板才能印钞)
3.类与对象的关系
Java 对象和类 | 菜鸟教程 (runoob.com)
(1).类:类是一种抽象的数据类型,它是对一类事物整体描述/定义,但是并不能代表一个具体的事物;(如.动物,手机,电脑,公司,等等)
(2).对象:对象是抽象的具体实例;
(3).实例:显示生活中的一个东西,对抽象的东西(对象)进行表示出来的产物,是一个活生生存在的事物,他是唯一的。对象 >= 实例;(如.张大爷家的狗,路上的一个行人)
(4).属性:类中的变量和方法总称为属性,属性包括共性与特性;
可以简单理解为类是一个模板,对象是一个具体的实例;
4.对抽象的理解
抽象是指将具体的事物抽象出来;
其实说白了,抽象---》抽出相同特征的对象(实例), 他和具体又是相对的。
如.吃盖饭抽象的说就是吃饭,吃饭具体的说就是吃什么。人类具体的说就是分女人和男人,人类抽象的说就是动物;
二.提出问题养狗社区
面向过程(C语言) | 面向对象(Java) |
流水线(步骤) | 模块化(分类) |
一件事"该怎么做" | 一件事"该让谁来做" |
狗饿了,狗吃了食物 | 属性:狗、食物、饿;动作:狗吃食物 |
强调的是“吃”,“狗”只是一个参数 | 强调的是“吃”,“狗”只是一个参数 |
如果使用C语言写会非常麻烦,因为它是按照顺序来的,但是每一只狗的作息是不一样的,使用C语言的话每一只狗都要写一遍非常麻烦;
如果使用Java写,我们只需要把这些狗的共性和特性提取出来,形成一个个模块(如.吃,睡觉,等等),让狗主人自己填写狗的作息;
使用我们使用Java写养狗社区;
package com.microsoft.bean;// 狗类(狗属性)
public class Dogs {// 狗的状态// 下面每一个狗的状态,都是类中的一个成员,它们是类的重要组成部分;// 成员变量:它们组成和构成了类,所有我们这么命名// 狗名字public String name;// 狗种类public String variety;// 狗的年龄public int age;// 狗的食物public String food;// 狗的行为(就是狗的动作,在类中被称为行为)public void eat() {System.out.println(this.name+"狗吃饭");}public void sleep() {System.out.println(this.name+"狗睡觉");}public void run() {System.out.println(this.name+"狗正在奔跑");}}
一个项目只能有一个main方法,所以我们要定义一个测试文件为Application
import com.microsoft.bean.Dogs;public class Application {public static void main(String[] args) {// 张大爷家的狗是狗类中的一个实例// // 张大爷,注册APPDogs zhangDog = new Dogs();// 张大爷设置狗的状态zhangDog.name = "阿黄";zhangDog.variety = "中华田园犬";zhangDog.age = 2;zhangDog.food = "剩菜剩饭";// 张大爷设置狗现在的行为zhangDog.eat();}
}
三.方法与变量的分类
1.非静态变量与非静态方法
上面定义狗的一些状态与行为,没有使用Static,使用我们可以称为这些为非静态变量与非静态方法;
所以我们要调用时,要先实例化这个对象,所以new关键字
使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中的构造器的调用;(构造器我们后面会讲)
// 张大爷,注册APP,使用new实例化// 格式:对象类型 对象名 = new 对象值;Dogs zhangDog = new Dogs();// 张大爷设置狗的状态zhangDog.name = "阿黄";zhangDog.variety = "中华田园犬";zhangDog.age = 2;zhangDog.food = "剩菜剩饭";// 调用非静态变量:对象名.变量名System.out.println("张大爷家狗的名字: " + zhangDog.name);// 张大爷设置狗现在的行为// 调用非静态方法:对象名.方法名zhangDog.eat();
2.静态变量与静态方法
有Static关键字修饰的变量与方法,我们叫静态变量与静态方法;
// 狗所在的小区public static String plot = "希望小区";// 狗名字public String name;// 狗种类public String variety;// 狗的年龄public int age;// 狗的食物public String food;// 我们要给所以狗打疫苗public static void injection(){System.out.println("所以的狗,月底打疫苗");}
// 张大爷,注册APP,使用new实例化Dogs zhangDog = new Dogs();// 张大爷设置狗的状态zhangDog.name = "阿黄";zhangDog.variety = "中华田园犬";zhangDog.age = 2;zhangDog.food = "剩菜剩饭";// 调用静态变量使用:类名.变量名// 原因静态变量是属于整个类的,不属于某个对象System.out.println("张大爷的狗所在小区" +Dogs.plot);// 调用静态方法属于:类名.方法名// 原因静态方法是属于整个类的,不属于某个对象Dogs.injection();
四.注销账号和null空指针异常
// 张大爷,注册APPDogs zhangDog = new Dogs();// 张大爷家的狗是狗类中的一个实例// 张大爷设置狗的状态zhangDog.name = "阿黄";zhangDog.variety = "中华田园犬";zhangDog.age = 2;zhangDog.food = "剩菜剩饭";// 张大爷注销账号zhangDog = null;// 注销后就不能在调用否则会出现空指针异常System.out.println("张大爷家狗的名字: " + zhangDog.name);
NullPointerException
原因:指针原本指向张大爷家的狗,注销账号后指向一个空白的区域
五.简单内存分析
第一步:加载Application类与静态方法(从这里可以看出静态变量与方法与类一起加载,所有对象都可以使用),进入main函数
第二步:加载Dogs类
第三步:张大爷注册app,使用Dogs zhangDog = new Dogs();,在栈生成引用变量名,对象生成在堆里,堆里的对象是通过Dogs类为模板生成,引用变量名指向它在堆中的地址;
第四步:赋值
六.OOP封装
问题:
pubilc 公有的,公共的-------用户可以随意修改(如.上面张大爷注册账号时可以随意填写狗的信息,如果在里面的东西与钱挂钩的话,那么用户也可以随意修改)
解决:
private 私有的------用户不能随意修改,我们给一个用户能设置,能获取,但不能随意设置,使用getset关键字,快捷方式Alt+insert
Ctrl+a全选,然后回车
this表示:本身调用者这个对象
package com.microsoft.bean;public class Dogs {// 狗所在的小区public static String plot = "希望小区";// 狗名字private String name;// 狗种类private String variety;// 狗的年龄private int age;// 狗的食物private String food;// 约束public String getName() {return this.name;}public void setName(String name) {if (name.length() < 20) {this.name = name;}else {System.out.println("你的狗名字过长");}}public String getVariety() {return variety;}public void setVariety(String variety) {this.variety = variety;}public int getAge() {return age;}public void setAge(int age) {if (age > 0 && age <30){this.age = age;}else {System.out.println("你的狗年龄错误");}}public String getFood() {return food;}public void setFood(String food) {this.food = food;}// 我们要给所以狗打疫苗public static void injection(){System.out.println("所以的狗,月底打疫苗");}// 狗的行为(就是狗的动作,在类中被称为行为)public void eat() {System.out.println(this.name+"狗吃饭");}public void sleep() {System.out.println(this.name+"狗睡觉");}public void run() {System.out.println(this.name+"狗正在奔跑");}}
import com.microsoft.bean.Dogs;public class Application {public static void main(String[] args) {// 张大爷,注册APP,使用new实例化Dogs zhangDog = new Dogs();// 张大爷设置狗的状态// 输入使用setzhangDog.setName("阿黄");zhangDog.setVariety("中华田园犬");zhangDog.setAge(10);zhangDog.setFood("剩菜剩饭");// 输出使用getSystem.out.println(zhangDog.getAge());}
}
出现问题,每一个成员变量都要写getset非常麻烦,所有出现了一个架包
下载完插件后,我们要下载架包
架包网站:Maven Repository: org.projectlombok » lombok (mvnrepository.com)
选择版本,点进去,然后jar下载
引入架包
然后将架包拖进去,接着选择作用范围
第一个表示全局,第二个表示这个项目,第三个表示模块
如果想使用结包还要启用注解
使用:特殊的可以单写,这个叫方法的重写,我们后面会讲
package com.microsoft.bean;import lombok.Getter;
import lombok.Setter;// 也可以写在一个成员变量后,只对一个成员变量起作用
@Getter
@Setterpublic class Dogs {// 狗所在的小区public static String plot = "希望小区";// 狗名字private String name;// 狗种类private String variety;// 狗的年龄private int age;// 狗的食物private String food;// 方法的重写public void setName(String name) {if (name.length() < 20) {this.name = name;}else {System.out.println("你的狗名字过长");}}public void setAge(int age) {if (age > 0 && age <30){this.age = age;}else {System.out.println("你的狗年龄错误");}}// 我们要给所以狗打疫苗public static void injection(){System.out.println("所以的狗,月底打疫苗");}// 狗的行为(就是狗的动作,在类中被称为行为)public void eat() {System.out.println(this.name+"狗吃饭");}public void sleep() {System.out.println(this.name+"狗睡觉");}public void run() {System.out.println(this.name+"狗正在奔跑");}}
七.toString
// 张大爷设置狗的状态zhangDog.setName("阿黄");zhangDog.setVariety("中华田园犬");zhangDog.setAge(10);zhangDog.setFood("剩菜剩饭");// 如果我们想要输出张大爷家的狗所有信息需要写四条输出语句// 如果使用toString,我们只需写一条输出语句
快捷方式Alt+insert,然后全选,生成
@Overridepublic String toString() {return "Dogs{" +"name='" + name + '\'' +", variety='" + variety + '\'' +", age=" + age +", food='" + food + '\'' +'}';}
也可以直接使用架包引入
import lombok.ToString;// 也可以写在一个成员变量后,只对一个成员变量起作用
@ToString
效果
补充: 补充如果要使用图中三个方法,可以引入架包@Date
八.构造方法
问题:
张大爷想要在注册账号时,填写狗的基本信息
解决:
使用构造函数,初始化对象(实例);
/*类中的构造器也称为构造方法,是在进行创建对象(new)的时候必须调用的;构造器有两大特点:1.必须和类的名字相同2.必须没有返回值类型,也不能写void*/// 无参数构造函数(无参构造器),每创建一个类,都会有一个无参构造器;// 如果是系统自带的类会默认创建,要是自己引入的类需要自己,手动创建;public Dogs() {}// 有参数的构造函数(有参构造),一但定义有有参构造,无参构造就必须定义;// 有参构造使用了方法的重载public Dogs(String name, String variety, int age, String food) {this.name = name;this.variety = variety;this.age = age;this.food = food;}
import com.microsoft.bean.Dogs;public class Application {public static void main(String[] args) {// 张大爷,注册APP,并设置狗的基本信息Dogs zhangDog = new Dogs("阿黄","中华田园犬",10,"剩菜剩饭");System.out.println("张大爷家的狗所有信息" +zhangDog);}
}
总结:在创建对象时是有调用构造器来初始化值,无参构造默认存在,有参构造是方法重载;
快捷方式Alt+insert,然后选择初始化对象
九.垃圾回收机制
ava自动会进行垃圾回收,所有我们不用管
如果需要手动,使用:
System.gc();
十.关键字Static
问题:
静态变量与方法加private,会出现输出不了的问题;
解决:
public static String getPlotInstance(){return plot;}
静态不用写set
System.out.println("张大爷家狗住的小区:" +Dogs.getPlotInstance());
1.Static单例设计模式
单例设计模式是一种创建对象的设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问该实例;
简单来说就是:不提供new的方法,只提供对外操作的方法;
package com.microsoft.bean;public class Earth {// new 一个新的地球,自己new自己,只有Earth类内可以修改private static Earth earthInstance = new Earth();// 外部无法new新的Earthprivate Earth() {}// 提供外部操作方法public static Earth getEarthInstance(){return earthInstance;}public void showMessage(){System.out.println("Hello Earth!");}
}
// 获取唯一可用的对象Earth object = Earth.getEarthInstance();// 显示消息object.showMessage();
2.静态代码块
package com.microsoft.bean;public class Earth {{System.out.println("匿名代码块");}static {System.out.println("静态代码块");}public Earth() {System.out.println("构造方法");}public static void main(String[] args) {System.out.println("第一次调用");Earth temp = new Earth();System.out.println("\n第二次调用");Earth tempTwo = new Earth();}
}
原因:Static关键字是与类一起加载所有首先调用,接着是类中的匿名代码块,然后构造方法,
还有值得注意的是静态代码块只调用一次;
3.静态导入包
导入前调用方法:类名.方法
System.out.println(Math.random());
导入后调用方法:方法
import static java.lang.Math.random;System.out.println(random());
十一.内部类
1.成员内部类
package com.microsoft.bean;public class Earth {// 外部类public class Sun{// 内部类public void fuck() {System.out.println("这是内部类");}}}
// 创建内部类对象:可以在外部类中创建内部类的对象Earth earth = new Earth();Earth.Sun sun = earth.new Sun();// 调用sun.fuck();
2.静态内部类
package com.microsoft.bean;public class Earth {public static class Sun{public void fuck() {System.out.println("这是静态内部类");}}}
// 创建内部类对象:可以直接通过类名创建静态内部类的对象Earth.Sun temp = new Earth.Sun();temp.fuck();
3.局部内部类
package com.microsoft.bean;
public class Earth {public static void main(String[] args) {class drop{public void man() {}}}}
4.匿名内部类(没有名字的内部类)
这个要学完接口后,再回来看,这个一般用到接口上
这是我们第四课接口中用到例子
package com.microsoft.bean;public interface Human {// 接口中所有方法都是抽象的// 吃饭,每个地区饮食是不一样的public void eat();// 喝水,每个地区是不一样的public void drink();
}
我们可以不用创建一个新类,也可以实现接口,直接应用
import com.microsoft.bean.*;public class Application {public static void main(String[] args) {Human chinese = new Human() {@Overridepublic void eat() {System.out.println("吃中餐");}@Overridepublic void drink() {System.out.println("喝热水");}};chinese.eat();chinese.drink();}
}