面向对象编程-中级部分
8.1 IDE(集成开发环境)-IDEA
8.1.1IDEA 介绍
- IDEA 全称IntelliJ IDEA
- 在业界被公认为最好的Java 开发工具
- IDEA 是JetBrains 公司的产品,总部位于捷克的首都布拉格
- 除了支持Java 开发,还支持HTML,CSS,PHP,MySQL,Python 等
8.2 IDE(集成开发环境)-Eclipse
8.2.1Eclipse 介绍
- Eclipse 是一个开放源代码的、基于Java 的可扩展开发平台。
- 最初是由IBM 公司耗资3000 万美金开发的下一代IDE 开发环境
- 2001 年11 月贡献给开源社区
- Eclipse 是目前最优秀的Java 开发IDE 之一
8.3 IDE(集成开发环境)-IDEA 的使用
8.3.1 IDEA 的安装+pj教程
https://blog.csdn.net/m0_50736744/article/details/121272313
8.3.2 IDEA 使用技巧和经验
-
设置字体和颜色主题
菜单file -> settings
菜单file -> Apprarance -
字符编码设置,默认就是UTF-8。
8.3.3 课堂练习
使用IDEA 开发一个java 项目testpro01,创建一个类MyTools, 编写一个方法,可以完成对int 数组冒泡排序的功能。
学员练习, 使用快捷键的开发项目
8.3.4 IDEA 常用快捷键
- 删除当前行, 默认是ctrl + Y 自己配置ctrl + d
- 复制当前行, 自己配置ctrl + alt + 向下光标
- 补全代码alt + /
- 添加注释和取消注释ctrl + / 【第一次是添加注释,第二次是取消注释】
- 导入该行需要的类先配置auto import , 然后使用alt+enter 即可
- 快速格式化代码ctrl + alt + L
- 快速运行程序自己定义alt + R
- 生成构造器等alt + insert [提高开发效率]
- 查看一个类的层级关系ctrl + H [学习继承后,非常有用]
- 将光标放在一个方法上,输入ctrl + B 或者 ctrl+鼠标左键 , 可以定位到方法[学继承后,非常有用]
- 自动的分配变量名, 通过在后面加.var 或者 Alt+回车[老师最喜欢的]
- 还有很多其它的快捷键…
- redo撤销重做,默认ctrl+shift+z,修改成ctrl+y;
8.3.5 模板/自定义模板
8.4 包
8.4.1看一个应用场景
现在有两个程序员共同开发一个java项目,程序员xiaoming希望定义一个类取名Dog ,程序员xiaoqiang也想定义一个类也叫 Dog。两个程序员为此还吵了起来,怎么办?–>包
8.4.2包的三大作用
- 区分相同名字的类
- 当类很多时,可以很好的管理类[看Java API文档]
- 控制访问范围
8.4.3包基本语法
8.4.4包的本质分析(原理)
8.4.5 快速入门
8.4.6 包的命名
8.4.7常用的包
一个包下,包含很多的类,java 中常用的包有:
-
java.lang.* //lang 包是基本包,默认引入,不需要再引入.
例如求-1 的绝对值:Math.abs(-1),直接用 不用在代码前边import引入
例如:Math.PI -
java.util.* //util 包,系统提供的工具包, 工具类,使用Scanner
-
java.net.* //网络包,网络开发
-
java.awt.* //是做java 的界面开发,GUI
8.4.8 如何引入包
com.hspedu.pkg : lmport01.java
语法: import 包;
我们引入一个包的主要目的是要使用该包下的类
比如import java.util.Scanner;就只是引入一个类Scanner。
import java.util.*;1/表示将java.util包所有都引入
建议:我们需要使用到哪个类,就导入哪个类即可,不建议使用 *导入
package com.hspedu.pkg;
import java.util.Arrays;
//import java.util.Scanner; //表示只会引入java.util 包下的 Scanner
//import java.util.*;//表示将java.util 包下的所有类都引入(导入)
public class Import01 {
public static void main(String[] args) {
//使用系统提供 Arrays 完成 数组排序
int[] arr = {-1, 20, 2, 13, 3};
//比如对其进行排序
//传统方法是,自己编写排序(冒泡)
//系统是提供了相关的类,可以方便完成 Arrays
Arrays.sort(arr);
//输出排序结果
for (int i = 0; i < arr.length ; i++) {
System.out.print(arr[i] + "\t");
}
}
}
8.4.9 注意事项和使用细节
pkgDetail.java
- package的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只有一句package。
- import指令位置放在package的下面,在类定义前面,可以有多句且没有顺序要求。
//package的作用是声明当前类所在的包,需要放在类(或者文件)的最上面,
// 一个类中最多只有一句package
package com.hspedu.pkg;
//import指令 位置放在package的下面,在类定义前面,可以有多句且没有顺序要求
import java.util.Scanner;
import java.util.Arrays;
//类定义
public class PkgDetail {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[] arr = {0, -1, 1};
Arrays.sort(args);
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
8.5 访问修饰符
8.5.1基本介绍
java 提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围):
- 公开级别:用public 修饰,对外公开
- 受保护级别:用protected 修饰,对子类和同一个包中的类公开
- 默认级别:没有修饰符号,向同一个包的类公开.
- 私有级别:用private 修饰,只有类本身可以访问,不对外公开.
8.5.2 4种访问修饰符的访问范围
背下来
- 修饰符可以用来修饰类中的属性,成员方法以及类
- 只有默认的和public才能修饰类!,并且遵循上述访问权限的特点。
- 因为没有学习继承,因此关于在子类中的访问权限,我们讲完子类后,再回头讲解
- 成员方法的访问规则和属性完全一样.
//com.hspedu.modifier:需要很多文件来说明(A类,B类, Test类…)
modifier包中的A类:
package com.hspedu.modifier;
public class A {
//四个属性,分别使用不同的访问修饰符来修饰
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
public void m1() {
//在同一类中,可以访问public protected 默认 private 修饰属性和方法
System.out.println("n1=" + n1 + " n2=" + n2 + " n3=" + n3 + " n4=" + n4);
}
protected void m2() { }
void m3() { }
private void m4() { }
public void hi() {
//在同一类中,可以访问public protected 默认 private 修饰属性和方法
m1();
m2();
m3();
m4();
}
}
modifier包中的B类:
package com.hspedu.modifier;
public class B {
public void say() {
A a = new A();
//在同一个包下,可以访问 public , protected 和 默认修饰属性或方法,不能访问private 属性或方法
System.out.println("n1=" + a.n1 + " n2=" + a.n2 + " n3=" + a.n3 );
a.m1();
a.m2();
a.m3();
//a.m4(); 错误的
}
}
modifier包中的主类Test:
package com.hspedu.modifier;
public class Test {
public static void main(String[] args) {
A a = new A ();
a.m1();
B b = new B();
b.say();
}
}
//只有 默认和public 可以修饰类
class Tiger{ }
pkg包里的主类:(不同包)
package com.hspedu.pkg;
import com.hspedu.modifier.A;
public class Test {
public static void main(String[] args) {
A a = new A();
//在不同包下,可以访问public 修饰的属性或方法
//但是不能访问 protected ,默认,private修饰的属性或方法
System.out.println(a.n1);
a.m1();
//不能访问 a.m2() a.m3() a.m4()
}
}
8.6 面向对象编程三大特征
面向对象编程有三大特征:封装、继承和多态。
8.6.1 封装介绍
封装(encapsulation)就是把抽象出的数据[属性] 和对数据的操作[方法] 封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作[方法],才能对数据进行操作。
8.6.2 封装的理解和好处
- 隐藏实现细节:方法(连接数据库)<–调用(传入参数…)
- 可以对数据进行验证,保证安全合理
Person {name, age]
Person p = new Person();
p.name = “jack” ;
p.age = 1200; //(有人活1200岁不合理)
8.6.3 封装的实现步骤(三步)
8.7 快速入门案例
请大家看一个小程序(com.hspedu.encap: Encapsulation01.java),不能随便查看人的年龄,工资等隐私,并对设置的年龄进行合理的验证。年龄合理就设置,否则给默认年龄,必须在1-120,年龄,工资不能直接查看,name的长度在2-6字符之间。
package com.hspedu.encap;
public class Encapsulation01 {
public static void main(String[] args) {
//如果要使用快捷键alt+r, 需要先配置主类
//第一次,我们使用鼠标点击形式运算程序,后面就可以用
Person person = new Person();
person.setName("韩顺平");
person.setAge(30);
person.setSalary(30000);
System.out.println(person.info());
System.out.println(person.getSalary());
//如果我们自己使用构造器指定属性
Person smith = new Person("smith", 800, 50000);
System.out.println("====smith的信息======");
System.out.println(smith.info());
}
}
/*
那么在java中如何实现这种类似的控制呢?
请大家看一个小程序(com.hspedu.encap: Encapsulation01.java),
不能随便查看人的年龄,工资等隐私,并对设置的年龄进行合理的验证。年龄合理就设置,否则给默认
年龄, 必须在 1-120, 年龄, 工资不能直接查看 , name的长度在 2-6字符 之间
*/
class Person {
public String name; //名字公开
private int age; //age 私有化
private double salary; //..
public void say(int n,String name) {
}
//构造器 alt+insert
public Person() {
}
//有三个属性的构造器
public Person(String name, int age, double salary) {
// this.name = name;
// this.age = age;
// this.salary = salary;
//我们可以将set方法写在构造器中,这样仍然可以验证
setName(name);
setAge(age);
setSalary(salary);
}
//自己写setXxx 和 getXxx 太慢,我们使用快捷键
//然后根据要求来完善我们的代码.
public String getName() {
return name;
}
public void setName(String name) {
//加入对数据的校验,相当于增加了业务逻辑
if(name.length() >= 2 && name.length() <=6 ) {
this.name = name;
}else {
System.out.println("名字的长度不对,需要(2-6)个字符,默认名字");
this.name = "无名人";
}
}
public int getAge() {
return age;
}
public void setAge(int age) {
//判断
if(age >= 1 && age <= 120) {//如果是合理范围
this.age = age;
} else {
System.out.println("你设置年龄不对,需要在 (1-120), 给默认年龄18 ");
this.age = 18;//给一个默认年龄
}
}
public double getSalary() {
//可以这里增加对当前对象的权限判断
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
//写一个方法,返回属性信息
public String info() {
return "信息为 name=" + name + " age=" + age + " 薪水=" + salary;
}
}
8.7.1 将构造器和setXxx 结合
有三个属性的构造器
public Person(String name, int age, double salary) {
// this.name = name;
// this.age = age;
// this.salary = salary;
//我们可以将set 方法写在构造器中,这样仍然可以验证
setName(name);
setAge(age);
setSalary(salary);
}
8.7.2 课堂练习
public class TestAccount {
public static void main(String[] args) {
//创建Account
Account account = new Account();
account.setName("jack");
account.setBalance(60);
account.setPwd("123456");
account.showInfo();
//如果我们自己使用构造器指定属性
Account cm = new Account("cm", 25, "111111");
cm.showInfo();
}
}
/**
* 创建程序,在其中定义两个类:Account和AccountTest类体会Java的封装性。
* Account类要求具有属性:姓名(长度为2位3位或4位)、余额(必须>20)、
* 密码(必须是六位), 如果不满足,则给出提示信息,并给默认值(程序员自己定)
* 通过setXxx的方法给Account 的属性赋值。
* 在AccountTest中测试
*/
public class Account {
//为了封装,将3个属性设置为private
private String name;
private double balance;
private String pwd;
//提供两个构造器
public Account() {
}
public Account(String name, double balance, String pwd) {
this.setName(name);
this.setBalance(balance);
this.setPwd(pwd);
}
public String getName() {
return name;
}
//姓名(长度为2位3位或4位)
public void setName(String name) {
if (name.length() >= 2 && name.length() <= 4) {
this.name = name;
} else {
System.out.println("姓名要求(长度为2位3位或4位),默认值 无名");
this.name = "无名";
}
}
public double getBalance() {
return balance;
}
//余额(必须>20)
public void setBalance(double balance) {
if (balance > 20) {
this.balance = balance;
} else {
System.out.println("余额(必须>20) 默认为0");
}
}
public String getPwd() {
return pwd;
}
//密码(必须是六位)
public void setPwd(String pwd) {
if (pwd.length() == 6) {
this.pwd = pwd;
} else {
System.out.println("密码(必须是六位)默认密码为 000000");
this.pwd = "000000";
}
}
//显示账号信息
public void showInfo() {
//可以增加权限的校验
System.out.println("账号信息 name=" + name + " 余额=" + balance + " 密码" + pwd);
// if() {
// System.out.println("账号信息 name=" + name + " 余额=" + balance + " 密码");
// }else{
// System.out.println("你无权查看...");
// }
}
}
8.8 面向对象编程-继承
8.8.1 为什么需要继承
8.8.2 继承基本介绍和示意图
继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends 来声明继承父类即可。画出继承的示意图
8.8.3 继承的基本语法
8.8.4 快速入门案例
我们对Extends01.java 改进,使用继承的方法,请大家注意体会使用继承的好处
package com.hspedu.extend_.improve_;
import com.hspedu.extend_.Graduate;
import com.hspedu.extend_.Pupil;
public class Extends01 {
public static void main(String[] args) {
com.hspedu.extend_.Pupil pupil = new Pupil();
pupil.name = "银角大王~";
pupil.age = 11;
pupil.testing();
pupil.setScore(50);
pupil.showInfo();
System.out.println("=======");
com.hspedu.extend_.Graduate graduate = new Graduate();
graduate.name = "金角大王~";
graduate.age = 23;
graduate.testing();
graduate.setScore(80);
graduate.showInfo();
}
}
package com.hspedu.extend_.improve_;
//父类,是Pupil 和 Graduate的父类
public class Student {
//共有属性
public String name;
public int age;
private double score;//成绩
//共有的方法
public void setScore(double score) {
this.score = score;
}
public void showInfo() {
System.out.println("学生名 " + name + " 年龄 " + age + " 成绩 " + score);
}
}
package com.hspedu.extend_.improve_;
//让Pupil 继承 Student类
public class Pupil extends Student {
public void testing() {
System.out.println("小学生 " + name + " 正在考小学数学..");
}
}
package com.hspedu.extend_.improve_;
//让Graduate继承 Student 类
public class Graduate extends Student {
public void testing() {//和Pupil不一样
System.out.println("大学生 " + name + " 正在考大学数学..");
}
}
8.8.5 继承给编程带来的便利
- 代码的复用性提高了
- 代码的扩展性和维护性提高了
8.8.6 继承的深入讨论/细节问题
- 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问.[代码演示]
- 子类必须调用父类的构造器, 完成父类的初始化。
- 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过(怎么理解。) [举例说明]
- 如果希望指定去调用父类的某个构造器,则显式的调用一下: super(参数列表)
- super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)
- super() 和this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
- java 所有类都是Object 类的子类, Object 是所有类的基类.
- 父类构造器的调用不限于直接父类!将一直往上追溯直到Object 类(顶级父类)
- 子类最多只能继承一个父类(指直接继承),即java 中是单继承机制。
思考:如何让A 类继承B 类和C 类? 【先让A 继承B,再让B 继承C】 - 不能滥用继承,子类和父类之间必须满足is-a 的逻辑关系
代码
//package com.hspedu.extend_;
//第1,主类。
public class ExtendsDetail {
public static void main(String[] args) {
// System.out.println("===第1个对象====");
// Sub sub = new Sub(); //创建了子类对象 sub
// sub.sayOk();
// System.out.println("===第2个对象====");
// Sub sub2 = new Sub("jack"); //创建了子类对象 sub2
System.out.println("===第3对象====");
Sub sub3 = new Sub("king", 10); //创建了子类对象 sub2
}
}
//第2,父类。
//package com.hspedu.extend_;
public class Base extends TopBase { //父类
//4个属性
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
public Base() { //无参构造器
System.out.println("父类Base()构造器被调用....");
}
public Base(String name, int age) {//有参构造器
//默认super()
System.out.println("父类Base(String name, int age)构造器被调用....");
}
public Base(String name) {//有参构造器
System.out.println("父类Base(String name)构造器被调用....");
}
//父类提供一个public的方法,返回了n4
public int getN4() {
return n4;
}
public void test100() {
System.out.println("test100");
}
protected void test200() {
System.out.println("test200");
}
void test300() {
System.out.println("test300");
}
private void test400() {
System.out.println("test400");
}
//call
public void callTest400() {
test400();
}
}
//第3,子类。
//package com.hspedu.extend_;
import java.util.Arrays;
//输入ctrl + H 可以看到类的继承关系
public class Sub extends Base { //子类
public Sub(String name, int age) {
//1. 老师要调用父类的无参构造器, 如下或者 什么都不写,默认就是调用super()
//super();//父类的无参构造器
//2. 老师要调用父类的 Base(String name) 构造器
//super("hsp");
//3. 老师要调用父类的 Base(String name, int age) 构造器
super("king", 20);
//细节: super在使用时,必须放在构造器第一行
//细节: super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
//this() 不能再使用了
System.out.println("子类Sub(String name, int age)构造器被调用....");
}
public Sub() {//无参构造器
//super(); //默认调用父类的无参构造器,写不写都存在
super("smith", 10);
System.out.println("子类Sub()构造器被调用....");
}
//当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器
public Sub(String name) {
super("tom", 30);
//do nothing...
System.out.println("子类Sub(String name)构造器被调用....");
}
public void sayOk() {//子类方法
//非私有的属性和方法可以在子类直接访问
//但是私有属性和方法不能在子类直接访问
System.out.println(n1 + " " + n2 + " " + n3);//属性,再写n4就报错
test100();
test200();
test300();
//test400();方法,错误
//要通过父类提供公共的方法去访问
System.out.println("n4=" + getN4());
callTest400();//
}
}
//第4 顶级类Object
//package com.hspedu.extend_;
public class TopBase { //父类是Object
public TopBase() {
//super(); Object的无参构造器
System.out.println("构造器TopBase() 被调用...");//1
}
}
8.8.7 继承的本质分析(重要)
package com.hspedu.extend_;
/**
* 讲解继承的本质
*/
public class ExtendsTheory {
public static void main(String[] args) {
Son son = new Son();//内存的布局
//?-> 这时请大家注意,要按照查找关系来返回信息
//(1) 首先看子类是否有该属性
//(2) 如果子类有这个属性,并且可以访问,则返回信息
//(3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息..)
//(4) 如果父类没有就按照(3)的规则,继续找上级父类,直到Object...
System.out.println(son.name);//返回就是大头儿子
//System.out.println(son.age);//返回的就是39
System.out.println(son.getAge());//返回的就是39
System.out.println(son.hobby);//返回的就是旅游
}
}
class GrandPa { //爷类
String name = "大头爷爷";
String hobby = "旅游";
}
class Father extends GrandPa {//父类
String name = "大头爸爸";
private int age = 39;
public int getAge() {
return age;
}
}
class Son extends Father { //子类
String name = "大头儿子";
}
- 子类创建的内存布局
注意:
要按照查找关系来返回信息
(1) 首先看子类是否有该属性
(2) 如果子类有这个属性,并且可以访问,则返回信息
(3) 如果子类没有这个属性,就看父类有没有这个属性(如果父类有该属性,并且可以访问,就返回信息…)
(4) 如果父类没有就按照(3)的规则,继续找上级父类,直到Object…
8.8.8 课堂练习
- 案例1 ExtendsExercise01.java
public class zuoye {
public static void main(String[] args) {
B b=new B();//a , b name, b
}
}
class A {
A() { //父类的无参构造器
System.out.println("a");
}
A(String name) {
System.out.println("a name");
}
}
class B extends A {
B() {
this("abc");
System.out.println("b");
}
B(String name) {
//默认有 super();
System.out.println("b name");
}
}
-
案例2
-
案例3 ExtendsExercise03.java
编写Computer 类,包含CPU、内存、硬盘等属性,getDetails 方法用于返回Computer 的详细信息
编写PC 子类,继承Computer 类,添加特有属性【品牌brand】
编写NotePad 子类,继承Computer 类,添加特有属性【color】
编写Test 类,在main 方法中创建PC 和NotePad 对象,分别给对象中特有的属性赋值,以及从Computer 类继承的属性赋值,并使用方法并打印输出信息。
package com.hspedu.extend_.exercise;
//编写Computer类,包含CPU、内存、硬盘等属性,getDetails方法用于返回Computer的详细信息
public class Computer {
private String cpu; //没啥要求就private
private int memory;
private int disk;
public Computer(String cpu, int memory, int disk) {//有参构造器
this.cpu = cpu;
this.memory = memory;
this.disk = disk;
}
//返回Computer信息
public String getDetails() { //方法
return "cpu=" + cpu + " memory=" + memory + " disk=" + disk;
}
//因为是私有,快捷键插入get set
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public int getMemory() {
return memory;
}
public void setMemory(int memory) {
this.memory = memory;
}
public int getDisk() {
return disk;
}
public void setDisk(int disk) {
this.disk = disk;
}
}
package com.hspedu.extend_.exercise;
//编写PC子类,继承Computer类,添加特有属性【品牌brand】
public class PC extends Computer{
private String brand;
//这里IDEA 根据继承的规则,自动把构造器的调用写好
//这里也体现: 继承设计的基本思想,父类的构造器完成父类属性初始化
//子类的构造器完成子类属性初始化
public PC(String cpu, int memory, int disk, String brand) {
super(cpu, memory, disk);
this.brand = brand;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public void printInfo() {
System.out.println("PC信息=");
// System.out.println(getCpu() + getMemory() + getDisk());
//调用父类的getDetails方法,得到相关属性信息..
System.out.println(getDetails() + " brand=" + brand);
}
}
package com.hspedu.extend_.exercise;
public class ExtendsExercise03 {
public static void main(String[] args) {
PC pc = new PC("intel", 16, 500, "IBM");
pc.printInfo();
}
}
8.9 super 关键字
- 基本介绍
super 代表父类的引用,用于访问父类的属性、方法、构造器 - 基本语法
8.9.1 super 给编程带来的便利/细节
- 调用父类的构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子
类初始化)。 - 当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须
通过super。如果没有重名,使用super、this、直接访问是一样的效果![举例] - super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用
super去访问爷爷类的成员;如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。A->B->C,当然也需要遵守访问权限的相关规则
注意1:A是父类,里边有个 cal 方法。B是子类。 希望子类B调用父类A 的cal方法。规则如下:
这时,因为子类B没有cal方法,因此我可以使用下面三种方式
找cal方法时(cal() 和 this.cal()),顺序是:
(1)先找本类,如果有,则调用
(2)如果没有,则找父类(如果有,并可以调用,则调用)
(3)如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 Object类
提示:如果查找方法的过程中,找到了,但是不能访问, 则报错, cannot access
如果查找方法的过程中,没有找到,则提示方法不存在
// cal();
this.cal(); //等价 cal()
//(super.call()) 找cal方法的顺序是直接查找父类,本类的cal不会调用,其他的规则一样
super.cal();
注意2:A是父类,里边有个 n1 属性。B是子类。 希望子类B调用父类A 的 n1 属性。规则如下:
演示访问属性的规则
n1 和 this.n1 查找的规则是
(1) 先找本类,如果有,则调用
(2) 如果没有,则找父类(如果有,并可以调用,则调用)
(3) 如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 Object类
提示:如果查找属性的过程中,找到了,但是不能访问, 则报错, cannot access
如果查找属性的过程中,没有找到,则提示属性不存在
System.out.println(n1);
System.out.println(this.n1);
// (super.n1) 找n1的顺序是直接查找父类属性,其他的规则一样
System.out.println(super.n1);
代码:
package com.hspedu.super_;
public class Base { //父类是Object
public int n1 = 999;
public int age = 111;
public void cal() {
System.out.println("Base类的cal() 方法...");
}
public void eat() {
System.out.println("Base类的eat().....");
}
}
package com.hspedu.super_;
public class A extends Base{
//4个属性
//public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
private int n4 = 400;
public A() {}
public A(String name) {}
public A(String name, int age) {}
// public void cal() { //计算方法
// System.out.println("A类的cal() 方法...");
// }
public void test100() {
}
protected void test200() {
}
void test300() {
}
private void test400() {
}
}
package com.hspedu.super_;
public class B extends A {
public int n1 = 888;
//编写测试方法
public void test() {
//super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;
// 如果多个基类(上级类)中都有同名的成员,使用super访问遵循就近原则。A->B->C
System.out.println("super.n1=" + super.n1);
super.cal();
}
//访问父类的属性 , 但不能访问父类的private属性 [案例]super.属性名
public void hi() {
System.out.println(super.n1 + " " + super.n2 + " " + super.n3 );
}
public void cal() {
System.out.println("B类的cal() 方法...");
}
public void sum() {
System.out.println("B类的sum()");
//希望调用父类-A 的cal方法
//这时,因为子类B没有cal方法,因此我可以使用下面三种方式
//找cal方法时(cal() 和 this.cal()),顺序是:
// (1)先找本类,如果有,则调用
// (2)如果没有,则找父类(如果有,并可以调用,则调用)
// (3)如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 Object类
// 提示:如果查找方法的过程中,找到了,但是不能访问, 则报错, cannot access
// 如果查找方法的过程中,没有找到,则提示方法不存在
//cal();
this.cal(); //等价 cal()
//找cal方法(super.call()) 的顺序是直接查找父类,本类的cal不会调用,其他的规则一样
//super.cal();
//演示访问属性的规则
//n1 和 this.n1 查找的规则是
//(1) 先找本类,如果有,则调用
//(2) 如果没有,则找父类(如果有,并可以调用,则调用)
//(3) 如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到 Object类
// 提示:如果查找属性的过程中,找到了,但是不能访问, 则报错, cannot access
// 如果查找属性的过程中,没有找到,则提示属性不存在
System.out.println(n1);
System.out.println(this.n1);
//找n1 (super.n1) 的顺序是直接查找父类属性,其他的规则一样
System.out.println(super.n1);
}
//访问父类的方法,不能访问父类的private方法 super.方法名(参数列表);
public void ok() {
super.test100();
super.test200();
super.test300();
//super.test400();//不能访问父类private方法
}
//访问父类的构造器(这点前面用过):super(参数列表);只能放在构造器的第一句,只能出现一句!
public B() {
//super();调父类的无参构造器
//super("jack", 10);调父类的第3个构造器
super("jack"); //调父类的第2构造器
}
}
package com.hspedu.super_;
public class Super01 {
public static void main(String[] args) {
B b = new B();//子类对象
b.sum();
// b.test();
}
}