文章目录
- 包
- 访问修饰符
- 封装
- 继承
- 继承使用细节
- 继承内存布局及细节
- Super
- super使用细节
- super与this比较
- overwrite
- 多态
- 对象的多态:
- 向上转型:
- 向下转型:
- 多态细节
- 动态绑定机制
- Object类
- ==
- equals
- hashcode
- toString
- finalize
包
区分相同名字的类,控制访问范围
基本语法:package 包名
包的本质,实际上就是 创建不同的文件夹 / 目录来保存类文件 \textcolor{green}{创建不同的文件夹/目录来保存类文件} 创建不同的文件夹/目录来保存类文件
包的命名:只能是 数字,字母,下划线,小圆点 , 不能用数字开头,不能是关键字或保留字 \textcolor{blue}{数字,字母,下划线,小圆点,不能用数字开头,不能是关键字或保留字} 数字,字母,下划线,小圆点,不能用数字开头,不能是关键字或保留字
一般 公司名.项目名.业务模块
package com.use //这句话的意思想当与下面的内容都在com.use包下面,//必须放在第一行,一个类且只能放在一个包下,包下可以有多个类
import com.lin * //表示引入com.lin包下的所有类(不推荐),impor语句放在package下,类定义之前
import com.xiaoqiang.Dog;//表示引入com.xiaoqiang包下的Dog类,一般来讲,用哪个就导入哪个
//import com.xiaohua.Dog; 错误
//编译器只能引用一个Dog类,这里会报错,要想使用xiaohua.Dog,创建的时候添加包名
public class Test{public static void main(String[] args){com.xiaoqiang.Dog dog=new com.xiaoqiang.Dog();System.out.println(dog);com.xiaohua.Dog dog1=new com.xiaohua.Dog();System.out.println(dog);}
}
访问修饰符
用于控制方法和属性的访问权限,也可以修饰类,但是只有 p u b l i c 和默认 \textcolor{blue}{用于控制方法和属性的访问权限,也可以修饰类,但是只有public和默认} 用于控制方法和属性的访问权限,也可以修饰类,但是只有public和默认
1.public:对外公开
2.protected:对子类和同一个包中的类公开
3.默认:没有修饰符,向同一个包中的类公开
4.private:只有类本身可以访问,不对外公开
封装
封装把抽象出的数据(属性)和对数据的操作(方法)封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作(方法),才能对数据进行操作;
1. 隐藏实现细节 \textcolor{blue}{1.隐藏实现细节} 1.隐藏实现细节
2. 可以对数据进行验证 \textcolor{blue}{2.可以对数据进行验证} 2.可以对数据进行验证
实现步骤:
1.将属性进行私有化private(不能直接修改属性)
2.提供一个公共public的set方法,用于对属性的判断修改x
public void setXxx(类型名 参数名){
//数据验证
属性=参数名;
}
3.提供一个公共public的get方法,用于获取属性的值
public XX getXxx(){
return xx;
}
package com.hspedu.encap;public class Encapsulation01 {public static void main(String[] args) { 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", 80, 50000);System.out.println("====smith的信息======");System.out.println(smith.info());}
}
/*
不能随便查看人的年龄,工资等隐私,并对设置的年龄进行合理的验证。年龄合理就设置,否则给默认
年龄, 必须在 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+insertpublic 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 太慢,我们使用快捷键alt+insert//然后根据要求来完善我们的代码.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;}
}
继承
继承可以解决代码复用,当 多个类存在相同属性和方法时,可以从这些类中抽象出父类 \textcolor{blue}{多个类存在相同属性和方法时,可以从这些类中抽象出父类} 多个类存在相同属性和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类
继承基本语法:
class 子类 extends 父类{
}
public class Extends01 {public static void main(String[] args) {Pupil pupil = new Pupil();pupil.name = "银角大王~";pupil.age = 11;pupil.testing();pupil.setScore(50);pupil.showInfo();System.out.println("=======");Graduate graduate = new Graduate();graduate.name = "金角大王~";graduate.age = 23;graduate.testing();graduate.setScore(80);graduate.showInfo();}
}
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);}
}class Pupil extends Student {//继承父类的子类public void testing() {System.out.println("小学生 " + name + " 正在考小学数学..");}
}class Graduate extends Student {//继承父类的子类public void testing() {//和Pupil不一样System.out.println("大学生 " + name + " 正在考大学数学..");}
}
继承使用细节
1.子类继承了父类所有的属性和方法, 非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类 \textcolor{blue}{非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类} 非私有的属性和方法可以在子类直接访问,但是私有属性和方法不能在子类
直接访问。要通过父类提供公共的方法去访问 \textcolor{blue}{直接访问。要通过父类提供公共的方法去访问} 直接访问。要通过父类提供公共的方法去访问
2.子类必须调用父类的构造器,完成父类的初始化。
3.当创建子类对象时,不管使用子类的哪个构造器, 默认情况下总会去调用父类的无参构造器。 \textcolor{blue}{默认情况下总会去调用父类的无参构造器。} 默认情况下总会去调用父类的无参构造器。如果父类 没有 \textcolor{blue}{没有} 没有提供无参构造器, 则必须在子类的构造器中使用 s u p e r 去指定使用父类的哪个构造器完成对父类的初始化工作, \textcolor{blue}{则必须在子类的构造器中使用super去指定使用父类的哪个构造器完成对父类的初始化工作,} 则必须在子类的构造器中使用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则编译不会通过。
4.如果希望指定去调用父类的某个构造器,则显式的调用一下:super()
5.supper在使用时需要放在构造器第一行。
6. s u p p e r ( ) 和 t h i s ( ) 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器。 \textcolor{blue}{supper()和this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器。} supper()和this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器。
7.JAVA所有类都是Object 类的子类。
8.父类构造器的调用不限于直接父类,将一直往上追溯到Object类。
9.子类最多 只能继承一个父类,但可以 A 继承 B , B 继承 C ,这样相当于 A 继承了 B , C \textcolor{blue}{只能继承一个父类,但可以A继承B,B继承C,这样相当于A继承了B,C} 只能继承一个父类,但可以A继承B,B继承C,这样相当于A继承了B,C
public class ExtendsDetail {public static void main(String[] args) {
// System.out.println("===第1个对象====");
// Sub sub = new Sub(); //创建了子类对象 sub
// System.out.println("===第2个对象====");
// Sub sub2 = new Sub("jack"); //创建了子类对象 sub2System.out.println("===第3对象====");Sub sub3 = new Sub("king", 10); //创建了子类对象 sub2//sub.sayOk();}
}
class TopBase { //父类是Objectpublic TopBase() {//super(); Object的无参构造器System.out.println("构造器TopBase() 被调用...");//1}
}class Base extends TopBase { //父类//4个属性public int n1 = 100;protected int n2 = 200;int n3 = 300;private int n4 = 400;public Base() { //无参构造器//默认super()System.out.println("父类Base()构造器被调用....");}public Base(String name, int age) {//有参构造器//默认super()System.out.println("父类Base(String name, int age)构造器被调用....");}public Base(String name) {//有参构造器//默认super()System.out.println("父类Base(String name)构造器被调用....");}//父类提供一个public的方法,返回了n4public 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");}//父类提供一个public的方法,返回了test400()public void callTest400() {test400(); }
}
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);test100();test200();test300();//test400();错误//要通过父类提供公共的方法去访问System.out.println("n4=" + getN4());callTest400();//}}
继承内存布局及细节
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是private,会报错//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 = "大头儿子";
}
Super
super代表父类的引用,用于访问 父类的属性,方法,构造器 \textcolor{blue}{父类的属性,方法,构造器} 父类的属性,方法,构造器
super使用细节
1.访问父类的属性,但不能访问父类的private属性,super.属性名;
2.访问父类的方法,不能访问父类的private方法。super.方法名(参数列表);
3.访问父类的构造器,super(参数列表),只能放在构造器的第一句,只能出现一句
super与this比较
overwrite
方法覆盖(重写)就是子类有一个方法和父类的某个方法的名称,返回类型,参数一样,那么我们就说子类的方法覆盖了父类的方法
1. 子类方法的返回类型和父类方法的返回类型一样,或者是父类返回类型的子类, \textcolor{blue}{子类方法的返回类型和父类方法的返回类型一样,或者是父类返回类型的子类,} 子类方法的返回类型和父类方法的返回类型一样,或者是父类返回类型的子类,比如父类返回类型是Obeject,子类方法返回类型是String
public Object getInfo(){}//父类
public String getInfo(){}
2. 子类方法不能缩小父类方法的访问权限 \textcolor{blue}{子类方法不能缩小父类方法的访问权限} 子类方法不能缩小父类方法的访问权限(否则会报错)
protected void say(){} //父类
public void say(){}
多态
方法和对象具有多种形态,重载和重写也体现多态
对象的多态:
1.一个对象的编译类型和运行类型可以不一致
2.编译类型在定义对象时,就确定了,不能改变
3.运行类型可以改变
4. 编译类型看定义时 = 号的左边,运行类型看 = 号的右边 \textcolor{blue}{编译类型看定义时=号的左边,运行类型看=号的右边} 编译类型看定义时=号的左边,运行类型看=号的右边
Animal animal=new Dog();//animal编译类型是Animal,运行类型Dog
animal=new Cat();//animal的运行类型变成了Cat,编译类型仍然是Animal
多态的前提,是两个对象(类)存在继承关系
向上转型:
父类的引用指向子类的对象
语法:父类类型 引用名=new 子类类型()
特点:编译类型看左边,运行类型看右边
可以调用父类中的所有成员(遵守访问权限)
不能调用子类中特有成员;(编译阶段能调用哪些成员由编译类型决定)
方法的运行效果看子类(运行类型)的具体实现(和子类的调用规则一样,先从子类找)
属性没有重写之说!属性的值看编译类型
向下转型:
1. 语法:子类类型 引用名=(子类类型) 父类引用
2.只能强制父类的引用,不能强制父类的对象
( new()出来,就已经规定好了,无法改变,指向它的引用可以改)
3. 要求父类的引用必须指向的是当前目标类型的对象 \textcolor{blue}{要求父类的引用必须指向的是当前目标类型的对象} 要求父类的引用必须指向的是当前目标类型的对象
4.可以调用子类类型中所有的成员
多态细节
public class PolyDetail {public static void main(String[] args) {//向上转型: 父类的引用指向了子类的对象//语法:父类类型引用名 = new 子类类型();Animal animal = new Cat();Object obj = new Cat();//可以吗? 可以 Object 也是 Cat的父类//向上转型调用方法的规则如下://(1)可以调用父类中的所有成员(需遵守访问权限)//(2)但是不能调用子类的特有的成员//(#)因为在编译阶段,能调用哪些成员,是由编译类型来决定的//animal.catchMouse();错误//(4)最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法//,然后调用,规则我前面我们讲的方法调用规则一致。animal.eat();//猫吃鱼..animal.run();//跑animal.show();//hello,你好animal.sleep();//睡//希望可以调用Cat的 catchMouse方法//多态的向下转型//(1)语法:子类类型 引用名 =(子类类型)父类引用;//问一个问题? cat 的编译类型 Cat,运行类型是 CatCat cat = (Cat) animal;cat.catchMouse();//猫抓老鼠//(2)要求父类的引用必须指向的是当前目标类型的对象//Dog dog = (Dog) animal; //可以吗? 错误System.out.println("ok~~");}
}
public class Animal {String name = "动物";int age = 10;public void sleep(){System.out.println("睡");}public void run(){System.out.println("跑");}public void eat(){System.out.println("吃");}public void show(){System.out.println("hello,你好");}}
class Dog extends Animal {//Dog是Animal的子类}
class Cat extends Animal {public void eat(){//方法重写System.out.println("猫吃鱼");}public void catchMouse(){//Cat特有方法System.out.println("猫抓老鼠");}
}
public class PolyDetail02 {public static void main(String[] args) {//属性没有重写之说!属性的值看编译类型Base base = new Sub();//向上转型System.out.println(base.count);// ? 看编译类型 10Sub sub = new Sub();System.out.println(sub.count);//? 20}
}class Base { //父类int count = 10;//属性
}
class Sub extends Base {//子类int count = 20;//属性
}
class PolyDetail03 {public static void main(String[] args) {BB bb = new BB();System.out.println(bb instanceof BB);// trueSystem.out.println(bb instanceof AA);// true//instanceof,判断对象的运行类型是否为XX类型或其子类型//aa 编译类型 AA, 运行类型是BB//BB是AA子类AA aa = new BB();System.out.println(aa instanceof AA);//trueSystem.out.println(aa instanceof BB);//trueObject obj = new Object();System.out.println(obj instanceof AA);//falseString str = "hello";//System.out.println(str instanceof AA);System.out.println(str instanceof Object);//true}
}class AA {} //父类
class BB extends AA {}//子类
动态绑定机制
public class DynamicBinding {public static void main(String[] args) {//a 的编译类型 A, 运行类型 BA a = new B();//向上转型System.out.println(a.sum());//30System.out.println(a.sum1());//20}
}class A {//父类public int i = 10;//动态绑定机制:public int sum() {//父类sum()return getI() + 10;//20 + 10}public int sum1() {//父类sum1()return i + 10;//10 + 10}public int getI() {//父类getIreturn i;}
}class B extends A {//子类public int i = 20;// public int sum() {
// return i + 20;
// }public int getI() {//子类getI()return i;}// public int sum1() {
// return i + 10;
// }
}
Object类
==
1.判断基本类型,判断的是值是否相等
2.判断引用类型,判断的是地址是否相等,即判断是不是同一个对象
equals
是Obeject类中的方法,只能判断引用类型
默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等(Integer,String)
Person person1 = new Person("jack", 10, '男');//Person重写了equals
Person person2 = new Person("jack", 20, '男');
System.out.println(person1.equals(person2));//假
hashcode
哈希值主要根据地址号,不能完全等同
两个引用指向同一个对象,则哈希值是一样的
toString
默认返回:全类名(包名+类名)+@+哈希值的十六进制
直接输出一个对象时,toString方法会被默认调用
finalize
1.当对象被回收时,系统自动调用该对象的finalize方法,子类可以重写该方法,做一些释放资源的操作
2.什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象。就会使用垃圾 回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法。
3.垃圾回收机制的调用,是由系统来决定,也可以通过system.gc()主动触发垃圾回收机制。
public class Finalize_ {public static void main(String[] args) {Car bmw = new Car("宝马");//这时 car对象就是一个垃圾,垃圾回收器就会回收(销毁)对象, 在销毁对象前,会调用该对象的finalize方法//,程序员就可以在 finalize中,写自己的业务逻辑代码(比如释放资源:数据库连接,或者打开文件..)//,如果程序员不重写 finalize,那么就会调用 Object类的 finalize, 即默认处理//,如果程序员重写了finalize, 就可以实现自己的逻辑bmw = null;System.gc();//主动调用垃圾回收器System.out.println("程序退出了....");}
}
class Car {private String name;//属性, 资源。。public Car(String name) {this.name = name;}//重写finalize@Overrideprotected void finalize() throws Throwable {System.out.println("我们销毁 汽车" + name );System.out.println("释放了某些资源...");}
}