多个对象的内存图
/*
* Person类 : 描述了人这类事务的,不具体描述,抽象描述
* 描述人应该具有什么,但是不详细
*
* 属性: 变量 人的性别和年龄 成员变量
* 行为: 方法 人吃饭,睡觉行为 成员方法
*
* 属性和行为 : 类的成员 (组成类的一员)
*/
public class Person {
//人的姓名
String name ;
//人的年龄
int age;
//人的吃饭行为方法
public void eat() {
System.out.println("人在吃饭" + name +".."+age);
}
//人的睡觉行为
public void sleep() {
System.out.println("人在睡觉" + name +".."+age);
}
}
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();
p1.name = "张三";
p1.age = 20;
p2.name = "李四";
p2.age = 22;
p1.eat();
p1.sleep();
p2.eat();
p2.sleep();
}
封装
面向对象的程序设计中(oop),包含三大特征. 我们以后开发程序,必须要体现出面向对象的三大特征,没有体现出现三大特征,不是在用面向对象思想开发程序.
- 封装 (encapsulation)
- 继承 (extends)
- 多态 (polymorphic)
封装概念
- 封装的定义 : 隐藏具体的实现细节,对外暴露使用方式.
- 现实中的封装实例 , 笔记本就是例子, 硬件看不到,有什么不知道. 键盘,鼠标可以操作
封装的好处
- 提升安全性
- 提高程序的复用性
- 提高程序的可扩展
封装的实现
- 修饰符,也是权限修饰符 private (私有的)
- private成员修饰符,不能写在方法里面
- 被private修饰的成员,访问权限是最低的
- 私有修饰的成员,只能在本类使用,出去定义的类,就无效
- private私有的修饰,只是封装的一种体现形式,不能完全代表封装
提高公共的访问方式
- 方法的形式出现,定义公共方法,让外界访问私有修饰的成员
- 方法:对类的成员变量,赋值或者是取值操作
- 赋值方法名 : set开头
- 取值方法名 : get开头
/*
* setAge方法,对成员变量age赋值
* 值不一定是什么,方法传递参数
*/
public void setAge(int a) {
//a的值判断
if(a < 0 || a > 120) {
//自己定义值
age = 0;
}else {
age = a;
}
}
//定义方法.获取age值
public int getAge() {
return age;
}
标准的Person对象,私有修饰写法(一)
public class Person {
private String name;
private int age ;
/*
* name成员变量的get/set方法
* set方法是赋值的,方法传递参数
* get方法是获取值,无参数,有返回值
*/
public void setName(String n) {
name = n;
}
public String getName() {
return name;
}
/*
* age成员变量的get/set方法
* set方法是赋值的,方法传递参数
* get方法是获取值,无参数,有返回值
*/
public void setAge(int a) {
age = a;
}
public int getAge() {
return age;
}
}
public static void main(String[] args) {
//创建Person类对象,调用方法get/set ,赋值和取值操作
Person p = new Person();
p.setName("张三");
p.setAge(20);
System.out.println( p.getAge() );
System.out.println( p.getName() );
}
方法的变量和类的成员变量同名
方法中的变量 (方法体定义的,和参数中定义),只属于这个方法,不属于其他的任何成员
方法中没有定义的变量,使用变量,找成员位置变量
public class Person {
private String name;
private int age = 1;
/*
* setAge(int a) 阅读性, 变量a不好理解
* 见名知意
*/
public void setAge(int age) {
age = age;
}
public int getAge() {
return age;
}
}
public static void main(String[] args) {
//创建Person类对象,调用方法get/set ,赋值和取值操作
Person p = new Person();
p.setAge(20);
System.out.println( p.getAge());
}
this关键字
this翻译为这个,这里.
this程序中的含义 : this表示当前对象的引用 (this本质上理解为就是一个对象)
this理解为 : 哪个对象调用的,this就表示哪个对象
-
this用法 : this用于区分成员变量和局部变量的同名问题
- this.变量名 : 表示类中的成员变量
- 变量名 : 表示方法的具备变量
public class Person {
private String name;
private int age = 1;
/*
* setAge(int a) 阅读性, 变量a不好理解
* 见名知意
* 区分出,哪个age是方法局部的,哪个age是类的成员的
* this关键字区分
*/
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
}
成员变量和局部变量区别
- 变量的定义上区别
- 局部变量定义在方法内部,方法参数
- 成员变量定义在方法外部,类的里面
- 变量的作用域上区别
- 局部变量作用在方法内部,作用在定义的一对{}里面
- 成员变量作用于整个的类中
- 变量的内存位置
- 局部变量,跟随的方法,进入方法栈
- 成员变量,跟随对象进入到堆内存
- 变量的生命周期不同
- 局部变量,跟随方法出栈,销毁,相对较短
- 成员变量,跟随对象进入到堆内存,等待JVM进行垃圾回收, 相对较长
- 变量的初始化值不同
- 局部变量,不赋值不能使用,没有默认值
- 成员变量,在堆内存,具有默认值的
标准的Person对象的写法(二)
/*
* Person类中,定义姓名和年龄成员
* 要求类的成员变量,私有的修饰
* 并提供get / set 使用
*
* 标准的写法,以后就这样写
*/
public class Person {
private String name;
private int age;
/*
* 成员变量,提供get/set方法
*/
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 static void main(String[] args) {
//创建Person类对象,调用方法get/set ,赋值和取值操作
Person p = new Person();
p.setAge(20);
System.out.println( p.getAge());
p.setName("李四");
System.out.println(p.getName());
}
构造方法
构造方法,称为构造器 (Constructor). 构造方法也是方法,作用是创建对象的时候使用,可以为对象进行初始化操作.
构造方法定义和作用
- 权限修饰符
- 构造方法,没有返回值类型, void不能写
- 构造方法的名字,有严格限制,必须和类名一致 (一模一样)
- 构造方法不需要return语句
- 作用 : 在创建对象的时候使用,其他的情况,和构造方法无关
- 构造方法的允许, new对象的时候才运行,只运行一次
/*
* 构造方法的定义
*
* - 权限修饰符
- 构造方法,没有返回值类型, void不能写
- 构造方法的名字,有严格限制,必须和类名一致 (一模一样)
- 构造方法不需要return语句
*/
public class Person {
//没有参数构造方法
public Person() {
System.out.println("无参数构造方法");
}
public void eat() {
System.out.println("人在吃饭");
}
}
构造方法实现对象的初始化
什么是对象的初始化操作 : 在对象的创建过程中,在new对象的时候,使用构造方法,为成员变量赋值,这个动作就称为对象的初始化操作!
/*
* 使用构造方法,对象初始化操作
* 为类中的成员变量赋值
*/
public class Person {
private String name;
private int age;
/*
* 为类中的成员变量赋值
* 成员变量的值,未知的,传递参数
* 参数接收姓名和年龄
*/
public Person(String name, int age) {
this.name = name;
this.age = age;
}
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 void eat() {
System.out.println("人在吃饭");
}
}
public static void main(String[] args) {
//创建Person类对象
//建立对象,就是在调用构造方法
//构造方法需要传递参数
Person p = new Person("张三",20);
System.out.println(p);
p.eat();
//调用方法get获取,成员变量的值
System.out.println(p.getName());
System.out.println(p.getAge());
}
思考问题
构造方法已经完成了,对象初始化操作中,成员变量赋值了,我们是否还需要set方法赋值 ?
肯定需要,以后修改成员变量的数据,使用set方法来实现
构造方法的内存
构造方法也是方法,运行必须进入栈内存
构造方法的调用者是创建的对象 (创建对象,称为实例化对象), 对象会将地址,传递到构造方法的this关键字
对象的半初始化
对象进入内存,成员变量赋值,默认值,到达这个步骤,称为对象的半初始化状态!
对象的创建顺序 :
对象先在堆内存中,划分空间 (内存地址有了)
初始化成员变量,赋值默认值,赋值定义的值
对象调用构造方法,为成员变量赋值
对象才会将地址,赋值到引用变量
p
默认构造方法
对于任何的一个类,都必须具有构造方法.
- 默认构造方法
- 在一个类中,如果我们不去定义构造方法,产生一个默认的构造方法,是有编译器javac添加的
- 默认构造方法 : 无参数的构造方法
public 构造方法名(){}
- 如果我们自己手写了构造方法,默认的就没有了
- 显示定义构造方法
- 我们自己的写的构造方法,称为显示定义,无论构造方法是怎么写的,默认的就没有了
构造方法的重载
构造方法也有重载特性 : 同一个类中,允许定义多个同名的方法,参数列表不同,就是重载.
构造方法同样可以定义多个,只要他们之间重载即可
/*
* 构造方法的重载特性
*/
public class Person {
private String name ;
private int age;
/*
* 带有String和int类型的构造方法
*/
public Person(String name , int age) {
this.name = name;
this.age = age;
System.out.println("有参数的构造方法String和int");
}
//再次定义构造方法,必须是重载形式的,无参数
public Person() {
System.out.println("无参数的构造方法");
}
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 void eat() {
System.out.println("人在吃饭");
}
}
public static void main(String[] args) {
//创建Person对象,使用无参数构造方法
Person p = new Person();
p.setName("张三");
p.setAge(20);
System.out.println(p.getName());
System.out.println(p.getAge());
//创建Person对象,调用有参数的构造方法
Person p2 = new Person("李四",22);
System.out.println(p2.getName());
System.out.println(p2.getAge());
}
this语句
this的另一种用法 :
- this.成员变量,区分成员变量和局部变量同名
- 语句用法
this()
- this语句的使用
-
this()
只能写在构造方法的有效代码第一行 -
this()
语句用来在构造方法中,去调用另一个构造方法 - this语句调用哪个构造方法,看(传递的哪些参数)
-
public Person(String name , int age) {
//调用无参数的构造方法
this();
this.name = name;
this.age = age;
System.out.println("有参数的构造方法String和int");
}
public Person() {
//调用有参数的构造方法
//this();
System.out.println("无参数的构造方法");
}
继承
继承,英语(extends) 扩展; 延伸
通过一个例子,引出概念
学生和老师案例出现了重复的程序, 共性进行了抽取,放在了另一个类中(Person类).只要学生类,老师类和Person类产生了某些关系,就直接可以使用Person类的内容了
产生出了父子关系
, 在程序中称为继承关系
继承 : 类和类之间产生的关系,继承关系. 包含了父和子.
生活中的继承和程序中继承关系
实现继承
继承的关键字 extends
, 一个类继承另一个类,使用该关键字
继承的定义格式 :
public class A(子类) extends B(父类){
}
术语 :
- A类,继承B类, A称为B的子类,又称为派生类
- B类,称为A的父类,又称为超类,基类
继承后 : 子类可以直接使用他父类的成员,不是全部
/*
* 父类 : 定义类,子类共有的内容
* 成员变量,私有修饰
* 外面的类都不能使用了,包含子类
* 提供get / set
*/
public class Person {
private String name;
private int age;
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 class Student extends Person{
}
public class Teacher extends Person{
}
public static void main(String[] args) {
Student stu = new Student();
//stu对象,是Person的子类的对象
//子类的对象,调用父类的成员
stu.setName("张三"); //父类继承的
stu.setAge(20);
System.out.println(stu.getName()); //父类继承的
System.out.println(stu.getAge());
Teacher tea = new Teacher();
//tea对象,是Person的子类的对象
tea.setName("李四");
tea.setAge(50);
System.out.println(tea.getName());
System.out.println(tea.getAge());
}
继承的好处
- 继承是共性的抽取
- 继承有效的减少代码量
- 提高程序的复用性和扩展性
- 面向对象的第三大特征多态, 多态的实现前提就是继承
继承的弊端
- 继承后,类和类之间的耦合性增强 (紧密连接性)
- 一个类继承另一个类后,不能再继承其他类了 (单继承弊端)
Java中的单继承
- Java语言只支持单继承,不支持多继承
- 一个类只能同时继承另一个类
- Java语言支持多层继承,称为多重继承