面向对象
核心:面向对象 类 对象 封装
拓展:对象创建 匿名对象
java:用来执行class文件
javac:用来将java文件编译为class文件
1.面向对象前言
1.1 概念
面向对象其实是一种编程思想,通过它可以把生活中复杂的事情变得简单化,从原来的执行者变成了指挥者
面向对象是基于面向过程而言的
面向过程强调的是过程 比如:
打开冰箱门
把大象放进去
关上冰箱门
(强调的是 把大象放入冰箱的过程)
面向对象强调的是结果 比如:
什么样的冰箱?什么样的大象?谁负责把大象装进去?(强调的是结果及对象 而不管过程)
1.2 面向对象的三大特征
- 封装性:把相关数据封装成一个“类”组件
- 继承性:是子类自动共享父类属性和方法,这是类之间的一种关系
- 多态: 同一个行为具有多个不同表现形式或形态的能力。
2.类和对象
2.1 类
- Java最基本的单位是类
- 类是一类事物的抽象
- 类是一个模板,他是描述一类对象的行为和状态
2.2 对象
每个对象具有三个特点:对象的状态,对象的行为和对象的标识。
- 对象的状态用来描述对象的基本特征。
- 对象的行为用来描述对象的功能.
- 对象的标识是指对象在内存中都有一个唯一的地址值用来和其他对象区分开来。
- 类是一类事物的抽象,对象是具体的实现。
2.3 类和对象的关系
- 计算机语言来怎么描述现实世界中的事物的? 属性 + 行为
- 那怎么通过Java语言来描述呢?通过类来描述一类事物,把事物的属性当做成员变量,把行为当做方法
2.4 对象在内存中的存储
- Java把内存分成5大区域,我们重点关注栈和堆
一般来讲局部变量存在栈中,方法执行完毕内存就被释放
对象(new出来的东西)存在堆中,对象不再被使用时,内存才会被释放
每个堆内存的元素都有地址值
对象中的属性都是有默认值的
TIPS: 栈与队列指的是一种数据的结构。
栈:先进后出(FILO – First In Last Out)
队列:先进先出(FIFO – First In First Out)
//创建类 Phone
class Phone{
//特征(属性)--类的成员变量来描述--位置:类里方法外
String brand;//品牌
double price;//价格
//行为(功能)--类的方法来描述--修饰符 返回值类型 方法名(参数列表){方法体}
public void call(String a) {
String s = a;
System.out.println(s);
System.out.println("正在打电话");
}
public void message() {
System.out.println("正在发短信");
}
}
public class Test1_ClassExec {
public static void main(String[] args) {
//new一个局部变量p(用来保存对象的地址 只是个名字并不能代表对象)
Phone p = new Phone();
//3.通过.来完成对象功能的调用
p.brand = "adad";
p.call(p.brand);
p.message();
//4.通过.来查看对象的属性值
System.out.println(p.brand);
System.out.println(p.price);
}
}
就是先到栈内存中找到p中保存的唯一的地址值
然后根据地址值找到Phone对象,并对其对应的属性值进行修改
例如:p.message();
也是先到栈内存中找到p中保存的唯一的地址值
然后根据地址值找到Phone对象,执行Phone对象的message()方法
3.封装
3.1 概述
-
封装是隐藏对象的属性和实现细节,仅仅对外提供公共的访问方式,比如类和方法
好处:
- 提高安全性
- 提高重用性
3.2 private关键字
-
是一个权限修饰符 ,可以用来修饰成员变量和成员方法.
-
私有是针对类,而不是针对对象,也就是说,同一个类的所有的不同的对象之间,可以互相访问别的对象的的私有的成员.
-
被私有化的成员只能在本类中访问
-
TIPS:如何封装?封装后的资源如何访问?
我们可以使用private关键字来封装成员变量与方法,如何访问私有资源?
关于成员变量:
-
setXxx对外提供公共的设置值方式
-
getXxx对外提供公共的获取值方式
关于成员方法:
把私有方法放在公共方法里供外界调用即可
-
【可以看到】
① private int age 使用了 private 关键字
② 相应的要使用 setAge 来设定更加精确和自由的属性规则; “setAge”的格式是一定的,“set” 为小写,使用 private 关键字的属性是“age”,所以“Age”的第一个字母要大写,这是特定的规则。 例如,如果你要对“name”这个属性进行同样的 private 操作,那么,你应该构成 “setName” 和 “getName” 一对方法来进行操作。但是! 布尔型的方式有例外,比如说你设置了一个布尔型的属性 “name”,那么,当你要对他使用 private 关键字的时候,你使用的一对方法名称应该叫做 “setName” 和 “isName” 而不是上文提到的 “getName”③ “setAge” 的相应要求是: 无返回值,有传入参数
⑤ “getAge”的相应要求是: 有返回值,无传入参数,结合第③条,这两条规则也是规定的!!不能改变所以,在对象的实例中(也就是箭头指向的部分),不再使用<图1>中简单的 person.age 来进行对象属性的设定和提取,而是 改成了person.setAge() 来设定 / person.getAge() 来提取。这样可以对属性的 age 有更加精细化的规定和设计,而不再局限于 int 属性所规定的范围。
================================================
PS: 如果使用 private 的关键字,而不用setAge和getAge方法,那么在对象中,无法使用age这个属性
- Eclipse 快速生成getxxx setxxx 右键空白处–>Source–>Genreate Getters and Setters–>select All–>Generate生成即可
4.创建对象
4.1 流程
Person p = new Person();//短短这行代码发生了很多事情
把Person.class文件加载进内存
在栈内存中,开辟空间,存放引用变量p
在堆内存中,开辟空间,存放Person对象
对成员变量进行默认的初始化
对成员变量进行显示初始化
执行构造方法(如果有构造代码块,就先执行构造代码块再执行构造方法)
堆内存完成
把堆内存的地址值赋值给变量p ,p就是一个引用变量,引用了Person对象的地址值
4.2 匿名对象
没有名字的对象,是对象的简化表示形式。
使用场景:
当被调用的对象只调用一次时(多次会创建多个对象浪费内存)
Demo d = new Demo();
d.sleep();
d.game();
//这个d就是对象的名字。
也可以写成:
new Demo().show();//创建了一个对象调方法
new Demo().game();//又创建了一个对象调方法
5.构造方法
5.1 概念
构造方法是一种特殊的方法,它是一个与类同名且没有返回值类型的方法
对象创建就是通过构造方法完成的,主要功能是完成对象的创建或者对象的初始化
当类创建对象(实例化)时,会自动调用构造方法
构造方法与普通方法一样也可以重载.
5.2 形式
与类同名,且没有返回值类型,可以含参也可以不含参
修饰符 方法名(方法名与类名相同)([参数列表])
{
代码
}
package cn.tedu.oop;
/**本类用于测试构造方法*/
public class Test1_Constructor {
//4.在公共类中创建入口函数
public static void main(String[] args) {
//5.创建Person类的对象进行测试
/**1.每次new(实例化)对象时会自动调用构造方法*/
Person p = new Person();
System.out.println(p.name);
System.out.println(p.age);
System.out.println(p.address);
p.eat();
Person p2 = new Person("海绵宝宝");
System.out.println(p2.name);
System.out.println(p2.age);
System.out.println(p2.address);
p.eat();
Person p3 = new Person("派大星",3,"海底");
System.out.println(p3.name);
System.out.println(p3.age);
System.out.println(p3.address);
p.eat();
}
}
//1.创建Person类,用来描述人这一类型
class Person{
//2.属性--创建成员变量
String name;//姓名
int age;//年龄
String address;//地址
/**2.默认存在无参构造,当new Person()会自动触发此无参构造*/
/**3.构造方法也存在重载的现象:方法的重载:在同一个类中,方法名相同且参数列表不同的现象*/
//普通方法的定义:修饰符 返回值类型 方法名 (参数列表){ 方法体 }
//构造方法的定义:修饰符 方法名 (参数列表){ 方法体 } --方法名与类名一致
//6.1创建无参构造--当new Person()时,会触发
public Person() {
System.out.println("我是Person类的无参构造");
}
/**快速向下复制:Ctrl+Alt+向下键*/
/**4.当只提供了含参构造,默认的无参构造会被覆盖,所以在创建重载的构造方法时,一定注意手动添加无参构造*/
//6.2创建1个参数的构造
public Person(String s) {
System.out.println("我是Person类的1个参数的构造方法"+s);
}
//6.3创建全参构造--定义了几个属性,就传几个参数,new Person("派大星",3,"海底");会触发
public Person(String n,int a,String addr) {
name = n;//n是局部变量,name是成员变量,把用户传的参数值n赋值给成员变量name
age = a;//a是局部变量,age是成员变量,把用户传的参数值a赋值给成员变量age
address = addr;//addr是局部变量,address是成员变量,把用户传的参数值addr赋值给成员变量address
System.out.println("我是Person类的全参构造");
}
//3.行为--创建方法
public void eat() {
System.out.println("到点啦,该点夜宵啦~");
}
}
5.3 构造代码块
- 构造代码块的特点
位置: 在类的内部,在方法的外部
作用: 用于抽取构造方法中的共性代码
执行时机: 每次调用构造方法前都会调用构造代码块
注意事项: 构造代码块优先宇构造方法加载
class Teacher{ String subject;//2.定义成员变量科目,全局生效 //6.定义构造代码块 { /**构造代码块的位置:类里方法外 * 作用:用于提取构造方法中的共性内容 * 执行时机:优先于构造方法执行*/ subject = "Java培优"; System.out.println("构造代码块"); } }
5.4 局部代码块
-
局部代码块特点
- 位置: 在方法里面的代码块
- 作用: 通常用于控制变量的作用范围,出了花括号就失效
- 注意事项: 变量的作用范围越小越好,成员变量会存在线程安全的问题
Class Teacher{
public void study() {
//7.创建局部代码块
/**局部代码块的位置:方法里
* 作用:控制变量的作用范围(作用范围越小越好,因为越小越安全)
* 执行时机:调用本方法时*/
{
int i = 10;
System.out.println(i);
}
//System.out.println(i);//报错,因为超出i的作用范围
System.out.println("正在备课...");
}
}
ps
代码块的作用:
- 静态代码块的作用:优先于对象加载,是随着类的加载就会第一时间加载进入内存,并且一直存在,直到类消失它才会消失专门用来完成一些需要第一时间加载并且只加载一次的资源
- 构造代码块是在创建对象时才会触发,专门用来提取构造方法的共性
- 局部代码块是在方法调用时才触发,专门用来控制变量的作用范围
{
int i = 10;
System.out.println(i);
}
//System.out.println(i);//报错,因为超出i的作用范围
System.out.println(“正在备课…”);
}
}
ps
代码块的作用:
1. 静态代码块的作用:优先于对象加载,是随着类的加载就会第一时间加载进入内存,并且一直存在,直到类消失它才会消失专门用来完成一些需要第一时间加载并且只加载一次的资源
2. 构造代码块是在创建对象时才会触发,专门用来提取构造方法的共性
3. 局部代码块是在方法调用时才触发,专门用来控制变量的作用范围