一、私有成员变量的访问和修改
重点来看数据的保护: 于是对于私有成员变量的访问,提供了两种方法,专门供外界来访问一个对象的私有成员变量 public get: 获取某一个成员变量的值 public set: 修改某一个成员变量的值 但是, 要注意,一个类中可以定义多个私有成员变量,而每一个成员变量,都对应一个get和set方法,为了表名 get和set和,它们所针对的那个成员变量的对应关系,有以下命名规则 成员变量名叫: xxx getXxx setXxx get,set方法带来的好处: 1. 通过get,set,可以访问对象的私有成员变量值 2. 通过get,set方法,完成对成员变量访问的读,写分离 3. 正式因为,外部只能通过get,set方法来访问私有成员变量, 可以以这种方式控制外部,对成员变量值访问 给对象成员变量赋初值: 1. 创建对象 对象名.成员变量1 = 值1 对象名.成员变量2 = 值2 ... 对象名.成员变量n = 值n 对于私有成员,以上方式,就失效了 对象名.setXxx(值) 无参构造 + set方法给对象成员变量值手动赋初值 2. 利用带参的构造方法
package com.cspratice.Object02;
public class test {
public static void main(String[] args) {
String name = "zhangsan";
Student student = new Student(name, 17, 1222);
// System.out.println(student.name);//无法访问私有成员变量
// name.method();//无法访问私有成员方法
System.out.println(student.getAge());//访问私有成员变量
student.setAge(17);//修改私有成员变量
System.out.println(student.getAge());
}
}
class Student{
private String name;
private int age;
private int num;
public Student(String name , int age , int num ) {//构造方法
this.name = name;
this.age = age;
this.num = num;
}
private void method(){
System.out.println("私有成员方法");
}
//alt + insert 快捷键
//得到Age
public int getAge() {
return age;
}
//修改Age属性
public void setAge(int age) {
if (age > 130 || age < 0) {//可以防止输入不合法
System.out.println("输入不合法");
return;
}
this.age = age;
}
}
二、继承
1、
/*
继承概述
Java中的继承和我们现实生活中的“继承”的含义基本类似,但是含义更广。
1.简单来说都可以表示“不劳而获”
2.类型之间“is a”的关系
a. 一种类型(类) 继承 另外一种类型(类)
子类 父类
b. 从数据类型,可以把子类类型,当做父类类型
从数据类型的角度,数据类型:一个数据集合和基于这个数据集合的一组操作
当子类继承父类,子类拥有了父类中定义的成员(父类中的数据集和基于数据集的操作)
c. 一个老师对象 是 一个人
被继承的类称之为父类(基类或超类),继承其他类的类称之为子类(派生类)
子类可以通过继承机制,不写任何额外代码就可以拥有父类的“所有”成员。
继承的语法
class 子类名 extends 父类名 {}
*/
public class Demo1Defination {
public static void main(String[] args) {
// 类型之间的"is a"
// 一个老师 是 一个人
Human human = new Teacher();
}
}
class Human {
String name;
}
// 继承别人的类,称之为子类,派生类
// 被继承的类,称之为父类,超类或基类
class Teacher extends Human {
}
2.
继承的注意事项: 子类只能访问父类所有非私有的成员(成员方法和成员变量) 子类不能继承父类的构造方法 Java继承的特点:在Java中只能实现单重继承。
3.隐藏问题
a.成员变量的隐藏问题
父类成员变量(field)的隐藏: 如果,在子类中,定义了和父类同名的成员变量 a. 在子类类体中,通过同名成员变量的变量名,访问到的是,子类中定义的同名成员变量值 看起来,就好像父类成员变量,在子类中,被隐藏起来了 b. 注意: 在父类方法的方法体中,通过变量名访问同名成员变量的值访问到的是,父类中定义的成员变量值 1. 在子类中是否可以定义和父类同名的成员变量? 可以 2. 如果可以,那么在子类中访问这个同名变量, 究竟访问到的是父类对象中的值,还是子类对象中的值? 子类中定义的同名成员变量值 如果在父类中访问呢? 父类中定义的同名成员变量值 3. 是否可以在子类对象中,同时访问到子类对象和父类对象中的同名成员变量的值? 可以,利用super关键字,可以在子类中,访问到继承自父类的成员变量值 在父类子类中,如果定义了同名成员变量,记住以下结论: 1. 如果在方法体中,通过同名成员的变量名,访问父类和子类定义的同名成员变量值 a. 如果是在父类的方法中,访问同名成员变量,访问到的就是父类的成员变量值 b. 如果实在子类的方法中,访问同名成员变量,访问到的就是子类成员变量的值 2. 在子类对象上,对象.的方式来访问成员变量的值,访问到的是子类中定义的同名成员变量值
public class test2 {
public static void main(String[] args){
B b = new B();
b.Acess2();//20
b.Acess1();//10
b.allAcess();//10 20
System.out.println(b.num);//20
}
}
class A{
int num = 10;
public void Acess1(){
System.out.println("1="+num);
}
}
class B extends A{
int num = 20;
public void Acess2(){
System.out.println("2= "+num);
}
public void allAcess(){
System.out.println("all = "+super.num);
System.out.println(num);
}
}
b.方法覆盖
父类方法的覆盖问题: 1. 子类中能否定义和父类一模一样的方法? 可以 2. 如果可以,那么在子类对象中访问这个一模一样 的方法, 究竟访问到的是父类对象中的方法,还是子类对象中的方法? 访问的是子类定义的方法 如果在父类中访问呢? 访问到的是还是子类中定义的一摸一样的方法 3. 是否可以在子类对象中,同时访问到子类对象和父类对象中的同名成员方法? 可以,使用super.方法的形式,在子类中调用父类中定义的一模一样的方法 解释一下,在jvm中所要确定索要执行的方法(在子类对象上调用方法) jvm是如何确定执行哪个方法的? a. 首先,会在子类对象对应的子类中去找,要执行的方法,如果找到,就直接执行。 b. 如果在子类中,没有找到,要执行的目标方法,才会在父类中这个方法。 所以,基于以上的方法执行的,搜索策略:所以因为在子类对象上,调用那个子类和父类一模一样的方法, 所以,永远先找到子类中定义的那个,一模一样的方法并执行。
发生方法覆盖的条件: 必须是在父类子类中定义一模一样的方法? 1. 访问权限 a. 子类方法的访问权限,不一定要和父类方法的访问权限一样 b. 子类方法的访问权限 >= 父类方法的访问权限 2. 方法返回值 a. 子类方法的方法返回值和父类方法的返回值相同 b. 子类方法的返回值可以不和父类方法的返回值相同, 子类方法的返回值类型 是 父类方法返回值类型的子类类型 3. 方法签名: 子类方法需要和父类方法相同
注意事项: 1.父类中私有方法不能被覆盖 2.静态方法不能被覆盖!! 可以利用@OVerride注解,来测试是否发生方法覆盖: 一旦我们给一个方法加@Override注解,就相当于在告诉编译,该方法一定覆盖父类的方法
4.子类对象初始化问题
/*
对于一个子类对象而言,其内存中的数据,分成了两部分:
1. 从父类中,继承下来成员变量的值
2. 子类中,自己定义的成员变量的值
子类对象的初始化问题(子类中成员变量(两部分)赋予初值先后顺序)
这两部分数据,在给他们赋初值的时候,谁先赋初值谁后赋初值(谁先初始化值,谁后初始化值)?
java语言的结论是,一定是 先 初始化子类对象中,继承的父类变量的值,后,初始化子类对象中,
子类自己定义的成员变量值
先父后子
为什么一定要先父后子:
a. 从直觉的角度,类比于现实生活,如果要继承父辈的财产,父辈得先存在,有一定的财富积累
b. 在实际开发中,我们子类成员变量的初值,依赖于父类成员变量值
如何实现,在子类对象中,先父后子的,成员变量值的初始化顺序呢?
核心思路:
1. 首先,构造方法本身的功能,就是初始化对象成员变量值的
2. 所以,显然,对我们只需要保证,父类的构造方法,先于子类的构造方法运行
3. 如何让父类构造方法,先于子类构造方法执行(在子类的构造方法的,第一条语句的位置,先去调用父类)
在子类对象初始化的过程中,保证先父后子的子类对象的初始化顺序:
1. 子类对象的隐式初始化方式(jvm来自动保证父类构造方法自动保证)
2. 子类对象的显示初始化方式(coder,通过写代码的方式保证,父类构造方法先执行)
*/
public class Demo1Introduction {
public static void main(String[] args) {
Student student = new Student();
// 访问继承父类的成员变量值
System.out.println(student.name);
// 访问子类自己定义的成员变量
System.out.println(student.studentId);
}
}
class Person {
// 姓名
String name;
int fatherI;
public void eat() {
System.out.println("吃饭ing");
}
public void sleep() {
System.out.println("睡觉ing");
}
}
// 利用继承使Student类 复用Person的类定义代码
class Student extends Person {
int studentId;
public Student() {
// 先调用父类构造方法
studentId = fatherI + 10;
}
public void study() {
System.out.println("学习ing");
}
}
/*
子类对象的显示初始化
如何调用调用父类的构造方法呢? 通过super关键字实现
super关键字: super代表父类对象的引用。
this关键字: 表示当前对象的引用 super关键字: super代表父类对象的引用。
this访问 当前对象的成员变量值 super 访问父类对象中,成员变量的值
this访问 当前对象的成员方法 super 访问父类对象,成员方法
this 调用 当前类中定义的构造方法 super 调用父类中定义的构造方法
this(实参列表) super(实参列表)
所以,总结一下,通过super关键子super(实参列表),调用到父类定义的构造方法。
如何实现子类对象的显示初始化?
只需要在子类构造方法的第一条语句,先调用父类的构造方法,在执行子类构造方法的方法体即可
注意事项:
1. 必须保证,子类每个构造方法,都要满足子类对象的初始化流程
2. 在子类构造方法中,通过super调用,父类构造方法时,该super语句,
必须出现在,子类构造方法第一条语句的位置
3. this()(调用当前类的构造方法) 和 super()(调用父类的构造方法)都可以,写在构造方法的方法体中, 它们都需要在第一条语句的位置
它们不能共存
4. 父类 成员变量初始化语句 构造代码块都,优先于子类中 成员变量的初始化语句,
构造代码块执行
*/
public class Demo1 {
public static void main(String[] args) {
// 创建子类对象
int sonI = 10;
int fatherI = 100;
ExplicitSon explicitSon = new ExplicitSon(sonI, fatherI);
//
// System.out.println(explicitSon.fatherI);
//
// System.out.println(explicitSon.sonI);
}
}
class ExplicitFather {
int fatherI;
/*
父类中定义的构造代码块
*/
{
System.out.println("father");
}
// public ExplicitFather() {
// this.fatherI = 100;
// }
public ExplicitFather(int fatherI) {
this.fatherI = fatherI;
}
}
class ExplicitSon extends ExplicitFather {
int sonI;
/*
子类中定义的构造代码块
*/
{
System.out.println("son");
}
public ExplicitSon (int sonI, int fatherI) {
// 先调用父类有参构造方法,必须出现在子类第一条语句的位置
super(fatherI);
this.sonI = sonI;
}
public ExplicitSon() {
super(10);
}
}