1 面向对象
1.1 概念
面向对象(Object Oriented)是软件开发方法,一种编程范式。面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD技术、人工智能等领域。面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。
面向对象是一种符合人类思维习惯的编程思想。现实生活中存在各种形态不同的事物,这些事物之间存在着各种各样的联系。在程序中使用对象来映射现实中的事物,使用对象的关系来描述事物之间的联系,这种思想就是面向对象。
1.1.1 面向对象和面向过程区分
面向对象:面向对象则是把构成问题的事务按照一定规则划分为多个独立的对象,然后通过调用对象的方法来解决问题。
比如:做好的饭,中间不管是谁把饭做好都能吃的找饭(简单说就是跳过执行的步骤直接得到结果)
面向过程:面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一一实现,使用的时候依次调用就可以了。
例如:把大象放进冰箱
- 先把冰箱门打开
- 把大象放进去
- 关上冰箱门
1.2 面向对象的三大特征
1.2.1 封装
封装是面向对象的核心思想,将对象的属性和行为封装起来,不需要让外界知道具体实现细节将相关的数据封装成一个“类”组件
1.2.2 继承
继承主要描述的就是类与类之间的关系,通过继承,可以在无需重新编写原有类的情况下,对原有类的功能进行扩展。
1.2.3 多态
多态指的是在一个类中定义的属性和功能被其他类继承后,当把子类对象直接赋值给父类引用变量时,相同引用类型的变量调用同一个方法所呈现出的多种不同行为特性。
2 类和对象
2.1 类
- Java语言最基本单位就是类,类似于类型。
- 类是一类事物的抽象。
- 可以理解为模板或者设计图纸。
抽象概念:类是对某一类事物的抽象描述,而对象用于表示现实中该类事物的个体。
2.2 对象
每个对象具有三个特点:对象的状态,对象的行为和对象的标识。
- 对象的状态用来描述对象的基本特征。
- 对象的行为用来描述对象的功能。
- 对象的标识是指对象在内存中都有一个唯一的地址值用来和其他对象区分开来。
- 类是一类事物的抽象,对象是具体的实现。
2.3 类与对象的关系
分析:可以将上图人看作是一个类,将每个具体的人(如小韩、小石等)看作对象,从人与具体个人之间的关系便可以看出类与对象之间的关系。
说明:类用于描述多个对象的共同特征,它是对象的模板,而对象用于描述现实中的个体,它是类的实例。对象是类的具体化,并且一个类可以对应多个对象
2.3.1 面向对象案例练习
public class TestCreateClass {
public static void main(String[] args) {
/**
* 通过new关键创建对应类的对象,
* 通过.来使用对象的资源
*/
Phone p = new Phone();
p.call();
p.message();
p.video();
System.out.println(p.brand);
System.out.println(p.color);
System.out.println(p.size);
System.out.println(p.price);
System.out.println("************************************");
Phone p2 = new Phone();
p2.brand = "华为";
p2.color = "玫瑰金";
p2.size = 5.6;
p2.price = 4999.99;
System.out.println(p2.brand);
System.out.println(p2.color);
System.out.println(p2.size);
System.out.println(p2.price);
p2.call();
p2.message();
p2.message();
}
}
/**封装:将一类事物的特征与行为封装成一个类组件*/
class Phone {
// 1、定义手机特点
/** 属性:通过成员变量来描述 */
String brand; // 品牌
String color; // 颜色
double size; // 尺寸
double price; // 价格
// 2、定义手机功能
/** 通过方法来描述 */
public void call() {
System.out.println("假装正在打电话....");
}
public void message() {
System.out.println("假装正在发短信");
}
public void video() {
System.out.println("真的在看直播");
}
}
3 对象在内存中的存储
Java把内存分成5大区域,我们重点关注栈和堆。
- 一般来讲局部变量存在栈中,方法执行完毕内存就被释放
- 对象(new出来的东西)存在堆中,对象不再被使用时,内存才会被释放
- 每个堆内存的元素都有地址值
- 对象中的属性都是有默认值的
TIPS: 栈与队列指的是一种数据的结构。
栈:先进后出(FILO – First In Last Out)
队列:先进先出(FIFO – First In First Out)
3.1 封装
3.1.1 概述
封装是面向对象的核心思想,将对象的属性和行为封装起来,不需要让外界知道具体实现细节将相关的数据封装成一个“类”组件
作用:
- 提高安全性
- 提高重用性
3.1.2 private关键字
private(当前类访问级别):如果类的成员被private访问控制符来修饰,则这个成员只能被该类的其他成员访问,其他类无法直接访问。类的良好封装就是通过private关键字来实现的。可以用来修饰成员变量和成员方法.被私有化的成员只能在本类中访问
3.1.3 分装案例练习1
package cn.tedu.oop;
/*本类用于测试封装的必要性*/
public class TestPrivate1 {
public static void main(String[] args) {
//5.创建对象进行测试
User u = new User();
u.name = "西门庆";
System.out.println(u.name);
//需要封装属性,如果不封装的话,就可以直接修改属性的值
//不需要按照我们预先设置好的方式也能操作
//u.money = 1000000;
//System.out.println(u.money);
u.setMoney(109999);
System.out.println(u.queryMoney());
}
}
//1.创建一个用户类User
class User{
//2.定义用户类的属性
public String name;
private double money = 10000;
//3.提供方法1:可以用来查询当前账户的余额
public double queryMoney(){
/*后续可以添加权限的校验*/
return money;
}
//4.提供方法2:可以设置当前账户的余额
public void setMoney(double money){
/*后续可以添加权限的校验*/
this.money = money;
}
}
3.1.4 封装案例练习2
/**
* 1、在java文件中可以创建对个class,但是被public修饰的类只能创建一个
* 并且这个java文件的名字必须以此公共类的名字一致
*/
/**
* 总结:
* 1、属性的封装:使用private关键字-- 提供了公共的get、set方法,提供了外界获取/设置属性值
* 2、方法的封装:使用private关键字-- 在本类的公共方法里调用这个私有方法
*/
public class TestPrivate {
public static void main(String[] args) {
Student s = new Student();
s.name = "紫霞";
s.sno = 5;
//s.subject = "政治";
System.out.println(s.name);
System.out.println(s.sno);
//System.out.println(s.subject);
//s.eat();
s.study();
s.setSubject("JAVA大数据");
System.out.println(s.getSubject());
}
}
/**
* 2、我们可以把一类事物的属性,功能封装到一个类组件中
*/
class Student {
/**
* 3、前提:为了提高程序的安全性以及调用要按照我们指定的方式来调用
* 说以我们可以封装自定义类中的属性与方法
*/
String name;
int sno;
/**
* 4.1、封装属性:通过private关键字进行封装
* 被private修饰的资源只能在本类中使用
*/
private String subject;
/**
* 4.2、添加被封装属性的get、set,方法也就是对外提供公共属性值获取/设置方法
*/
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public void study() {
System.out.println("假装在学C");
/**
* 5.2:在本类的公共方法里访问私有方法的功能
*/
eat();
}
/**
* 5.1:方法的封装:将方法的访问权限修改为private
*/
private void eat() {
System.out.println("正在干饭");
}
}
说明:如何访问被private
我们可以使用private关键字来封装成员变量与方法
关于成员变量方法访问:
- setXxx – 对外提供公共的设置值方式
- getXxx – 对外提供公共的获取值方式
关于成员方法:
把私有方法放在公共方法里供外界调用即可
4 构造方法
4.1 概念
构造方法是一种特殊的方法,它是一个与类同名且没有返回值类型的方法
构造方法的主要功能就是完成对象创建或者初始化
当类创建对象(实例化)时,就会自动调用构造方法
构造方法与普通方法一样也可以重载.
4.2 形式
与类同名,且没有返回值类型,可以含参也可以不含参
4.2.1 构造方法案例
public class TestConstructor {
public static void main(String[] args) {
/**
* 1、一个类会默认存在无参构造,每次实例化对象时都会自动调用构造方法
*/
Person p = new Person();
Person p2 = new Person("孙行者");
Person p3 = new Person("孙行者",800,"五行山B1");
System.out.println(p.name);
p.eat();
System.out.println(p3.name);
System.out.println(p3.age);
System.out.println(p3.address);
}
}
class Person {
String name;//姓名
int age;//年龄
String address;//地址
/**
* 2、构造方法格式:与类同名切没有返回值类型的方法
* 方法的格式:修饰符 返回值类型 方法名(参数列表) {方法体}
*/
public Person() {
System.out.println("我是无参构造");
}
/**
* 3、方法的重载:在同一个类中存在多个方法,方法名相同但参数列表不相同的现象
* 4、构造函数也存在重载现象
*/
public Person(String name) {
System.out.println("我是含参构造" + name);
}
public Person(String name, int age, String address) { // 形参
System.out.println("我是全参构造");
this.name = name;
this.age = age;
this.address = address;
}
public void eat() {
System.out.println("到饭点啦~该干饭啦~");
}
}
关于构造函数怎么记忆?
- 特点:方法名与类名相同,且没有返回值类型
- 执行时机:创建对象时立即执行
- 默认会创建无参构造,但是,如果自定义了含参构造,默认的无参构造会被覆盖,注意要手动添加哦
4.3 构造代码块与局部代码块
4.3.1 形式
{方法体…}
4.3.2 构造代码块的特点
- 位置: 在类的内部,在方法的外部
- 作用: 用于抽取构造方法中的共性代码
- 执行时机: 每次调用构造方法前都会调用构造代码块
- 注意事项: 构造代码块优先于构造方法加载
4.3.3 局部代码块
- 位置: 在方法里面的代码块
- 作用: 通常用于控制变量的作用范围,出了花括号就失效
- 注意事项: 变量的作用范围越小越好,成员变量会存在线程安全的问题
4.3.4 测试代码块的加载顺序
//执行顺序:
// 构造代码块——>构造方法——>对象创建成功——>局部代码块
/**
* 总结:
* 1、创建对象时,程序会自动调用构造方法,但是如果有构造代码块,会先执行构造代码块
* 提取所有构造的共性功能,在执行构造方法创建对象
* 2、对象创建好后,就可以通过对象来调用方法,如果方法中有局部代码块,就会执行对应的局部代码块
*/
public class TestBlock {
public static void main(String[] args) {
/**
* 每次实例化对象时,都会执行一次构造代码块
*/
Teacher t = new Teacher();
Teacher t1 = new Teacher();
Teacher t2 = new Teacher("政治");
t.teach();
}
}
class Teacher {
String subject;
//构建构造代码块
/**
* 构造代码块:
* 位置:类里方法外
* 执行时机:每次在调用构造方法是触发,而且要优先于构造方法执行
* 作用:用于提取所有构造方法的共性功能
*/
{
subject = "JAVA培优";
System.out.println("我是构造代码块");
}
public Teacher() {
System.out.println("无参构造" + subject);
}
/**
* 如果有多个构造方法被构造代码块提取了共性内容
* 但是个别的构造方法需要自己定义参数,这个时候可以把此参数名
* 设置为方法的参数,那么调用方法时,传什么值,就是什么值
*/
public Teacher(String subject) {
System.out.println("含参构造" + subject);
}
public void teach() {
System.out.println("正在授课ing....");
/**
* 局部代码块:
* 位置:方法里
* 执行时机:调用本代码块的所在方法时,才会触发
* 作用:控制变量的作用范围,变量的作用范围越小越好
*/
{
int i = 10;
System.out.println("局部代码块");
System.out.println(i);
}
//System.out.println(i);会报错,因为局部变量只能在局部使用
}
}
5 this关键字
5.1 概念
this代表本类对象的一个引用对象
5.2 形式
5.3 this练习之变量名相同时使用
public class TestThis1 {
public static void main(String[] args) {
Cat c = new Cat();
c.eat();
}
}
class Cat {
int sum = 20;
int s = 30;
public void eat() {
int sum = 10;
System.out.println(sum);// 变量的就近原则
System.out.println(s);
/**
* 当成员变量与局部变量同名时,我们可以通过this关键字,来指定成员变量
* 因为成员变量属于类资源,类消失,成员变量才会释放
* this代表的是本类,可以理解成Cat this = new Cat();
*/
System.out.println(this.sum);
}
}
5.3.1 this练习之构造方法间的调用
public class TestThis2 {
public static void main(String[] args) {
Dog d = new Dog(999);
//d.Dog();// 会报错:不能主动的在外部调用构造方法
}
}
/**
* this可以实现构造方法的调用
* 注意:是单方向的,不能来回调用,会死循环
* this();--调用本类的无参构造
* this(参数);--调用本类对应参数的含参构造
* this相关的语句必须写在第一行
*/
class Dog {
public Dog() {
/** 本行代码的作用:在无参构造中调用本类的含参构造 */
//this(6666);
System.out.println("无参构造");
}
public Dog(int n) {
this();
System.out.println("含参构造" + n);
}
}
5.4 OOP综合练习
public class TestOOP {
public static void main(String[] args) {
Teacher t1 = new Teacher();
Teacher t2 = new Teacher(666);
Teacher t3 = new Teacher("霞霞",18,1000000.00,"紫青宝剑");
}
}
class Teacher {
private String name;
private int age;
private double salary;
private String subject;
public Teacher() {
this(666);
System.out.println("我是Teacher类的无参构造");
}
public Teacher(int n) {
System.out.println("我是Teacher类的含参构造" + n);
// {
// 局部代码块:方法里,用于控制变量的范围
// }
}
public Teacher(String name, int age, double salary, String subject) {
System.out.println("我是Teacher类的全参构造");
this.name = name;
this.age = age;
this.salary = salary;
this.subject = subject;
}
public void ready() {
System.out.println("正在备课ing.....");
}
public void teach() {
System.out.println("正在授课ing.....");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
}
5.5 创建对象流程
Person p = new Person();//短短这行代码发生了很多事情
- 把Person.class文件加载进内存
- 在栈内存中,开辟空间,存放引用变量p
- 在堆内存中,开辟空间,存放Person对象
- 对成员变量进行默认的初始化
- 对成员变量进行显示初始化
- 执行构造方法(如果有构造代码块,就先执行构造代码块再执行构造方法)
- 堆内存完成
- 把堆内存的地址值赋值给变量p ,p就是一个引用变量,引用了Person对象的地址值