java封装、继承、多态笔记
1.包
1.包的命名规则
(1)只能包含数字、字母、下划线、小圆点.
(2)不能用数字开头,
(3)不能是关键字或保留字
例如:
demo.class.exec1 //错误class是关键字
demo.12a //错误,以数字开头
demo.ab12.oa // 对
命名规范实例:
一般是小写字母+小圆点(一般是com.公司名.项目名.业务模块名)
比如:
com.hspedu.oa.model;
com.hspedu.oa.controller;
举例:
com.sina.crm.user//用户模块
com.sina.crm.order//订单模块
com.sina.crm.utils //工具类
2.常用的包
一个包下,包含很多的类,java中常用的包有:
java.lang.* //lang包是基本包,默认引入,不需要再引入
java.util.* //util包,系统提供的工具包,工具类,使用 Scanner
java.net.* //网络包,网络开发
java.awt.* //是做java的界面开发,GUI
3.包引入的注意事项
一个类中最多只有一个package
package的作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只有一个package
2.访问修饰符
1.基本介绍
java提供四种访问控制修饰符号控制方法和属性(成员变量)的访问权限(范围)
1.公开级别:用public修饰,对外公开
2.受保护级别:用protected修饰,对子类和同一个包中的类公开
3.默认级别:没有修饰符号,向同一个包的类公开
4.私有级别:用private修饰,只有类本身可以访问,不对外公开
3.面向对象编程的三大特点:继承、封装和多态
1.封装
1.1 封装的定义
封装(encapsulation)就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作[方法],才能对数据进行操作。
1.2 封装的实现步骤的三部曲
1)将属性进行私有化private【不能直接修改属性】
2)提供一个公共的(public)set方法,用于对属性判断并赋值
public void setXxx(类型参数名){
//set方法用来设置或者修改属性值
//加入数据验证的业务逻辑属性=参数名;
}
3)提供一个公共的get方法,用于获取属性的值
public XX getXxx(){//权限判断
return xx;
}
1.3封装快速入门案例
案例一:
不能随便查看人的年龄,工资等隐私,并对设置的年龄进行合理的验证。
年龄合理就设置,否则给默认‘年龄必须在1-120,年龄,工资不能直接查看,name的长度在2-6之间
package com.hspedu.encap;
//不能随便查看人的年龄,工资等隐私,并对设置的年龄进行合理的验证。年龄合理就设置,否则给默认
//年龄必须在1-120,年龄,工资不能直接查看,name的长度在2-6之间
public class Encapsulation {
public static void main(String[] args) {
Person person = new Person();
person.name="li";
person.setAge(10);
person.setSalary(10000);
System.out.println(person.info());
}
}
class Person{
public String name;
private int age;
private double salary;
public void setName(String name){
if(name.length() >=2 && name.length() <=10)
this.name = name;
System.out.println("不合法");
}
public void setAge(int age) {
if(age < 1 || age > 120)
System.out.println("年龄不符合条件");
this.age = age;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getName(){
return name ;
}
public int getAge() {
return age;
}
public double getSalary() {
return salary;
}
//写一个方法返回字符串
public String info(){
return "信息为 name="+name+"age="+age+"salary="+salary;
}
}
案例二:
创建程序,在其中定义两个类:Account和AccountTest类,体会Java的封装性。
1.Account类要求具有属性:姓名(长度为2位3位或4位)、余额(必须>20)、密码(必须是六位),如果不满足,则给出提示信息,并给默认值
2.通过setXxx的方法给Account的属性赋值。
3.在AccountTest中测试
提示知识点:
String name= “”;int len = name.length();
package com.hspedu.encap;
public class Account{
String name;
double salary;
String pass;
public Account() {
}
public Account(String name, double salary, String pass) {
this.name = name;
this.salary = salary;
this.pass = pass;
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
public void setName(String name) {
if(name.length() == 2 || name.length() == 3 || name.length() == 4)
this.name = name;
}
public void setSalary(double salary) {
if(salary >= 20){
this.salary = salary;
}else {
this.salary = 0;
}
}
public void setPass(String pass) {
if(pass.length() == 6)
this.pass = pass;
else {
System.out.println("密码错误");
this.pass = "000000";
}
}
public String getPass() {
return pass;
}
public void showInfo(){
System.out.println("name =" + name + "salary =" + salary + "pwd =" + pass);
}
}
package com.hspedu.encap;
public class AccountTest {
public static void main(String[] args) {
Account account = new Account();
account.setName("ping");
account.setSalary(13);
account.setPass("123456");
account.showInfo();
}
}
2.继承
1.继承的基本介绍和示意图
继承可以解决代码复用,让我们的编程更加靠近人类思维。当多个类存在相同的属性(变量)和方法时,可以从这些类中抽象出父类,在父
类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可。
画出继承的示意图
2.继承的基本语法
class 子类 extends 父类{}
1)子类就会自动拥有父类定义的属性和方法
2)父类又叫超类,基类。
3)子类又叫派生类。
3.重点理解
1.子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类直接访问,要通过公共的方法去访问
拆分
(1)子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问,除了父类中的私有方法继承后无法使用,其与方法都可以使用
父类
package com.hspedu.extend_.improve;
//父类,是pupil和graduate的父类
public class Student {
//共有的属性
public String name;
private double score;
public int age;
//共有的方法
public void setScore(double score) {
this.score = score;
}
public void showInfo(){
System.out.println(age + "岁的" + name + "考试考了" + score);
}
}
子类:假设只有显示的某个信息不一样,这个信息是子类特有的
package com.hspedu.extend_.improve;
public class Pupil extends Student {
public void testInfo(){
System.out.println("小学生" + name + "正在考小学数学");
}
}
package com.hspedu.extend_.improve;
public class Graduate extends Student{
public void testInfo(){
System.out.println("大学生"+ name + "正在考大学数学");
}
}
测试
package com.hspedu.extend_.improve;
public class Test {
public static void main(String[] args) {
Pupil pupil = new Pupil();
pupil.name="li";
pupil.age = 10;
pupil.setScore(100);
pupil.testInfo();
pupil.showInfo();
System.out.println("==============");
Graduate graduate = new Graduate();
graduate.name = "ping";
graduate.age = 20;
graduate.setScore(98);
graduate.testInfo();
graduate.showInfo();
}
}
(2)但是私有属性和方法不能在子类直接访问
刚才的年龄是共有属性
//如果把父类中年龄改成私有的
private int age;
//测试中的这一行代码会出错
pupil.age = 10;
(3)解决上述问题:要通过公共的方法去访问
package com.hspedu.extend_;
public class Base {
//不同的属性
public int n1 = 100;
protected int n2 = 200;
int n3 = 300;
//n4是私有的,Sub无法直接拿到
private int n4 = 400;
//父类中提供了一个public的方法,返回了n4,通过这个方法,Sub类中就可以拿到n4的参数
public int getN4() {
return n4;
}
//无参构造器
public Base(){
System.out.println("父类的无参构造器Base()被调用....");
}
//不同的属性
public void Base1(){
System.out.println("Base1()...");
}
void Base02(){
System.out.println("Base2()...");
}
protected void Base03(){
System.out.println("Base03()...");
}
//在Sub中是无法获取的
private void Base4(){
System.out.println("Base4()....");
}
//可以通过这个方法来实现
public void callBase4(){
Base4();
}
}
测试
package com.hspedu.extend_;
public class Sub extends Base{
public Sub(){
// super();//默认调用父类的无参构造器,写不写都会被调用
System.out.println("子类的无参构造器Sub()被调用...");
}
public void ok(){
System.out.println("n1:"+ n1+ "\t n2:" + n2 + "\t n3:" + n3);
//由于Base下的n4是私有的,因此无法直接拿到,但是可以将私有的属性通过共有的方法让继承后类中使用
System.out.println("n4:"+getN4());
Base1();
Base02();
Base03();
//Base4的方法是私有的无法拿到,但是可以通过共有的方法那它在传到当前位置来
//Base4();
//在Base中使用了公共方法将其传入
callBase4();
}
}
2.子类必须调用父类的构造器,完成父类的初始化
//尽管Sub类中的方法没有调用父类的无参构造器,但是也会显示父类无参构造器相关信息,然后显示子类的无参构造器相关信息
//上面代码的片段
public class Sub extends Base{
public Sub(){
// super();//默认调用父类的无参构造器,写不写都会被调用
System.out.println("子类的无参构造器Sub()被调用...");
}
public Sub(String name ){
System.out.println("子类有参构造器Sub(String name )被调用");
}
}
测试:
3.当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在
子类的构造器中用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过[举例说明]
package com.hspedu.extend_;
public class Extendtail {
public static void main(String[] args) {
//尽管Sub类中的方法没有调用父类的无参构造器,但是也会显示父类无参构造器相关信息,然后显示子类的无参构造器相关信息
Sub sub = new Sub();
System.out.println("============");
Sub sub1 = new Sub();
// sub.ok();
}
}
测试结果:默认父类无参构造器会被调用
指定调用构造器
public class Base {
//无参构造器
// public Base(){
// System.out.println("父类的无参构造器Base()被调用....");
// }
public Base(String name, int age){
System.out.println("用的是父类第二个Base(String name, int age)");
}
}
public class Sub extends Base{
public Sub(){
// super();//默认调用父类的无参构造器,写不写都会被调用
//当父类的无参构造器被覆盖时,需要指定
//super在使用时,必须放在构造器的第一行
//super()和this()都只能放在构造器的第一行,因此这两个方法不能共存在一个构造器里面,第一行写了super(),就不能写this()
super("li",10);
System.out.println("子类的无参构造器Sub()被调用...");
}
public Sub(String name ){
//当父类的无参构造器被覆盖时,需要指定
super("chen",24);
System.out.println("子类有参构造器Sub(String name )被调用");
}
4.如果希望指定去调用父类的某个构造器,则显式的调用一下: super(参数列表)
5.super在使用时,必须放在构造器第一行(super)
6.super()和 this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
7.java所有类都是Object类的子类,Object是所有类的基类.
8.父类构造器的调用不限于直接父类!将一直往上追溯直到Object类(顶级父类)
9.子类最多只能继承一个父类(指直接继承),即java中是单继承机制。
思考:如何让A类继承B类和C类?
答案:A继承B,B在继承C
继承的本质:
/*
* (1)先查看子类是否有该属性
* (2)如果子类有该信息,并且可以访问,则返回信息
* (3)如果子类没有该属性,就看父类有没有这个属性,如果父类有该属性,并且可以访问,则返回父类的该信息
* (4)如果父类的该属性不可以访问,继续找上一级的父类,直到找到object
* */
问题:如果对象son要访问age这一属性,但是父类Father的age是私有的,爷爷类Grandpa的age是共有的,那么他能拿到爷爷的age吗?
不能!因为son在访问Father类的时候已经找到age这一 个属性了,但是由于是私有的无权访问,拿不到结果。它已经找到了,就不在想上找了,不会说无权访问就直接拿到grandpa类中的age属性。
4. super关键字
super代表父类的引用,用于访问父类的属性、方法、构造器
●基本语法
1.访问父类的属性,但不能访问父类的private属性【案例】 super.属性名;
2.访问父类的方法,不能访问父类的private方法【案例】super.方法名(参数列表);
3.访问父类的构造器(这点前面用过):super(参数列表);只能放在构造器的第一句,只能出现一句!
Super关键字
1.调用父类的构造器的好处(分工明确父类属性由父类初始化,子类的属性由子类初始化)
2.当子类中有和父类中的成员(属性和方法)重名时,为了访问父类的成员,必须通过super。如果没有重名,使用super、this、直接访问是一样的效果!
3.super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员;如果多个基类中都有同名的成员,使用super访问遵循就近原则。A->B->C,当然也需要遵守访问权限相关的规则
5.Super和this关键
3. 重写/覆盖
简单的说:方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么我们就说子类的这个方法覆盖了父类的方法
1.子类的方法的参数,方法名称,要和父类方法的参数,方法名称完全一样。
2子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类
比如父类返回类型是Object ,子类方法返回类型是String
【演示】
public class Animal {
public void ask(){
System.out.println("动物在叫唤.....");
}
public Object m1(){
return null;
}
}
public class Dog extends Animal {
public void cry(){
System.out.println("wangwang......");
}
//和public object m1()构成重写
public String m1(){
return null;
}
}
【练习一】:
1.编写一个Person类,包括属性 private (name、age),构造器、方法say(返回自我介绍的字符串)。
2.编写一个Student类,继承Person类,增加id、score属性private,以及构造器,定义say方法(返回自我介绍的信息)。
3.在main中,分别创建Person和Student对象,调用say方法输出自我介绍。
体会在子类中使用super()的好处
1.Person类,父类
package com.hspedu.override_;
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String say(){
return "我的名字是"+ name + "年龄是:" + age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
2.studen类
package com.hspedu.override_;
public class Student extends Person {
private int id;
private double score;
public Student(String name, int age, int id, double score) {
super(name, age);
this.id = id;
this.score = score;
}
public String say(){
return super.say() + "id= "+ id + "score = " +score;
}
public void setId(int id) {
this.id = id;
}
public void setScore(double score) {
this.score = score;
}
public int getId() {
return id;
}
public double getScore() {
return score;
}
}
3.测试
package com.hspedu.override_;
public class MainT {
public static void main(String[] args) {
Person person = new Person("li",18);
System.out.println(person.say());
System.out.println("====");
Student student = new Student("li",18,2203,80);
System.out.println(student.say());
}
}