包,修饰符,封装,继承,super,重写
1:包
1:包的作用:
1.区别相同名的类
2.当类很多时候更好的管理[API文档]
3.控制访问范围
2:包的命名
规则:数字,下划线,字母,小圆点。
规范:一般用小写字母来命名,(com.公司名.项目.业务模块名)
3:包的本质
包的本质就是一个个文件夹
scr包中放的是java源文件
out包中放的是java.class文件
4:包的基本语法
package表示打包
com.daiyang:表示包名
5:java中的包
java.lang.* //lang 包是基本包,默认引入,不需要再引入.
java.util.* //util 包,系统提供的工具包, 工具类,使用 Scanner
java.net.* //网络包,网络开发
java.awt.* //是做 java 的界面开发,GUI
6:导包
import 包名。
7:注意事项和使用细节
2:访问修饰符
1:种类
public:任何包都可以访问 不同包的子类 同一个包的不同类 同一个类
protected:不同包的子类可以访问 同一个包的不同类 同一个类
默认:同一个包的不同类
private:同一个类
java 提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围):
- 公开级别:用 public 修饰,对外公开
- 受保护级别:用 protected 修饰,对子类和同一个包中的类公开
- 默认级别:没有修饰符号,向同一个包的类公开.
- 私有级别:用 private 修饰,只有类本身可以访问,不对外公开
2:使用的注意事项
修饰符可以修饰属性,成员方法,构造器,类(类只能public和默认修饰)
成员方法修饰访问规则和属性一样
3:面向对象编程-封装
1:封装介绍
2:封装的实现步骤 (三步)
第一步:将属性私有化private修饰(不能直接修改属性)
3:实操案例
public class Worker {
private String name;
private int age;
private double salary;
public String getName() {
return name;
}
Scanner scanner=new Scanner(System.in);
public Worker(String name, int age, double salary) {
// this.name = name;
// this.age = age;
// this.salary = salary;
setName(name);
setAge(age);
setSalary(salary);
}
public void setName(String name) {
while(name.length()>6||name.length()<2) {
System.out.println("名字在2到6个字符之间,请重新输入");
name=scanner.nextLine();
return;
}
this.name = name;
}
public int getAge() {
//增加密码业务逻辑
return age;
}
public void setAge(int age) {
if (age<1||age>120) {
System.out.println("年龄范围在1到120");
return;
}
this.age = age;
}
public double getSalary() {
//增加业务密码逻辑
return salary;
}
public void setSalary(double salary) {
//增加密码业务逻辑
this.salary = salary;
}
}
将构造器和 setXxx 结合
public Worker(String name, int age, double salary) {
// this.name = name;
// this.age = age;
// this.salary = salary;
setName(name);
setAge(age);
setSalary(salary);
}
这样逻辑就更加严密,不会通过构造器来访问属性了
4面向对象编程-继承
继承是未来提高代码的复用,当两个事务如果有大量相同的属性和方法,比如人,每个人都有鼻子,腿,耳朵,等等,我们就可以把这个相同的属性和方法提取出来,创建一个父类,然后所有子类里面创建自己特有的属性和放法,通过extends来继承父类的属性和方法。
1:继承的基本语法
class 子类 extends 父类
子类会自动拥有父类的属性和方法
父类又叫超类,基类
子类又叫派生类
2:快速入门案例
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);
}
}
public class Pupil extends Student {
public void testing() {
System.out.println("小学生 " + name + " 正在考小学数学..");
}
}
public class Undergraduate extends Student{
public void testing() {//和 Pupil 不一样
System.out.println("大学生 " + name + " 正在考大学数学..");
}
}
代码的复用性提高了
代码的扩展性和维护性提高了
4:继承的深入讨论/细节问题
(1)子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问
这里注意的是子类是继承了所有的方法和属性,包括私有方法。
我们给name提供公共方法,子类用父类的公共方法来给name赋值
public class Student {
//共有属性
// public String name;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int age;
private double score;//成绩
//共有的方法
public void setScore(double score) {
this.score = score;
}
public void showInfo() {
System.out.println("学生名 " + name + " 年龄 " + age + " 成绩 " + score);
}
}
public class Test {
public static void main(String[] args) {
Undergraduate undergraduate=new Undergraduate();
Pupil pupil=new Pupil();
undergraduate.age=18;
undergraduate.setName("代阳");
undergraduate.setScore(100);
undergraduate.showInfo();
undergraduate.testing();
pupil.age=11;
pupil.setName("hha");
pupil.setScore(79);
pupil.showInfo();
pupil.testing();
}
}
(2) 子类必须调用父类的构造器, 完成父类的初始化
(3)当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用 super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过(怎么理解)
4) 如果希望指定去调用父类的某个构造器,则显式的调用一下 : super(参数列表)
5) super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)
6) super() 和 this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
7) java 所有类都是 Object 类的子类, Object 是所有类的基类. 8) 父类构造器的调用不限于直接父类!将一直往上追溯直到 Object 类(顶级父类)
9) 子类最多只能继承一个父类(指直接继承),即 java 中是单继承机制。
思考:如何让 A 类继承 B 类和 C 类? 【A 继承 B, B 继承 C】
10) 不能滥用继承,子类和父类之间必须满足 is-a 的逻辑关
11)ctrl+H可以看到类的继承关系
3:继承的本质分析(重要)
案例:
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 = "大头儿子";
}
4: super 关键字
基本介绍
super 代表父类的引用,用于访问父类的属性、方法、构造器
基本语法
super 给编程带来的便利/细节
如果查找属性的过程中,找到了,但是不能访问, 则报错, cannot access
// 如果查找属性的过程中,没有找到,则提示属性不存在
super 和 this 的区别比
5:方法重写/覆盖(override)
基本介绍:
1个子类里面的方法和父类的里面的一个方法,名字,返回类型相同,修饰符相同或者子类的权限大于父类,参数列表相同
注意事项和使用细节:
子类的方法名和参数列表要与父类的方法名和参数列表相同
子类的返回类型必须和父类的返回类型相同或者是父类返回类型的子类
子类的方法的修饰符权限必须相同或者大于父类
重载和重写的比较:
5:面向对象编程-多态
public class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Cat extends Animal{
public Cat(String name) {
super(name);
}
}
public class Dog extends Animal{
public Dog(String name) {
super(name);
}
}
public class Food {
private String name;
public Food(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Fish extends Animal{
public Fish(String name) {
super(name);
}
}
public class Bone extends Animal{
public Bone(String name) {
super(name);
}
}
public class Master {
private String name;
public Master(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void feed(Animal animal, Food food) {
System.out.println("主人 " + name + " 给 " + animal.getName() + " 吃 " + food.getName());
}
public void feed(Dog dog, Bone bone) {
System.out.println("主人 " + name + " 给 " + dog.getName() + " 吃 " + bone.getName());
}
public void feed(Cat cat, Fish fish) {
System.out.println("主人 " + name + " 给 " + cat.getName() + " 吃 " + fish.getName());
}
}
这种就是重载的多态
但是当种类很多时候
就要建立很多的方法,很不便捷
1:多[多种]态[状态]基本介绍
方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。
2:多态的具体体现
1) 方法的多态
public class PloyMethod {
public static void main(String[] args) {
//方法重载体现多态
A a = new A();
//这里我们传入不同的参数,就会调用不同 sum 方法,就体现多态
System.out.println(a.sum(10, 20));
System.out.println(a.sum(10, 20, 30));
//方法重写体现多态
B b = new B();
a.say();
b.say();
}
}
class B { //父类
public void say() {
System.out.println("B say() 方法被调用...");
}
}
class A extends B {//子类
public int sum(int n1, int n2){//和下面 sum 构成重载
return n1 + n2;
}
public int sum(int n1, int n2, int n3){
return n1 + n2 + n3;
}
public void say() {
System.out.println("A say() 方法被调用...");
}
}
2) 对象的多态 (核心,困难,重点)
几句重要的话:
一个对象的编译类型和运行类型可以不一致
编译类型在定义对象确定了,是不可变的
运行类型是可变的
等号左边的是编译类型,等号右边的运行类型
public class Animal {
public void cry() {
System.out.println("Animal cry() 动物在叫....");
}
}
public class Cat extends Animal {
public void cry() {
System.out.println("Cat cry() 小猫喵喵叫...");
}
}
public class Dog extends Animal{
public void cry() {
System.out.println("Dog cry()小狗汪汪叫");
}
}
public class Test {
public static void main(String[] args) {
//体验对象多态特点
//animal 编译类型就是 Animal , 运行类型 Dog
Animal animal = new Dog();
//因为运行时 , 执行到改行时,animal 运行类型是 Dog,所以 cry 就是 Dog 的 cry
animal.cry(); //小狗汪汪叫
//animal 编译类型 Animal,运行类型就是 Cat
animal = new Cat();
animal.cry(); //小猫喵喵叫
}
}
3:多态注意事项和细节讨论
多态的前提:两个类需要有继承关系
多态的向上转型:
本质:父类引用指向了子类
语法:父类 引用名=new 子类;
特点:不能调用子类特有的方法;
可以调用父类的全部方法(需要遵循访问权限)
最终运行情况看子类的具体实现;
多态的向下转型:
只能强转父类引用,不能强转父类对象
要求父类的引用指向强转的子类对象
向下转型后可以调用子类对象的所有方法;
public class Test {
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,运行类型是 Cat
Cat cat = (Cat) animal;
cat.catchMouse();//猫抓老鼠
//(2)要求父类的引用必须指向的是当前目标类型的对象
Dog dog = (Dog) animal; //可以吗?
//答案不行
System.out.println("ok~~");
}
属性没有重写之说!属性的值看编译类型
public class PolyDetail02 {
public static void main(String[] args) {
//属性没有重写之说!属性的值看编译类型
Base base = new Sub();//向上转型
System.out.println(base.count);// ? 看编译类型 10
Sub sub = new Sub();
System.out.println(sub.count);//? 20
}
}
class Base { //父类
int count = 10;//属性
}
class Sub extends Base {//子类
int count = 20;//属性
}
instanceOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型
public class PolyDetail03 {
public static void main(String[] args) {
BB bb = new BB();
System.out.println(bb instanceof BB);// true
System.out.println(bb instanceof AA);// true
//aa 编译类型 AA, 运行类型是 BB
//BB 是 AA 子类
AA aa = new BB();
System.out.println(aa instanceof AA);
System.out.println(aa instanceof BB);
Object obj = new Object();
System.out.println(obj instanceof AA);//false
String str = "hello";
//System.out.println(str instanceof AA);
System.out.println(str instanceof Object);//true
}
}
class AA {} //父类
class BB extends AA {}//子
4:java 的动态绑定机制(非常非常重要.)
Java 重要特性: 动态绑定机制
public class DynamicBinding {
public static void main(String[] args) {
//a 的编译类型 A, 运行类型 B
A a = new B();//向上转型
System.out.println(a.sum());//?40 -> 30
System.out.println(a.sum1());//?30-> 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() {//父类 getI
return 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;
// }
}
5:多态的应用
- 数组的定义类型为父类类型,里面保存的实际元素类型为子类类型
2)多态参数
6: Object 类详
1:equals 方法
==和 equals 的对比 [面试题]
2:hashCode 方法
1)提高具有哈希结构的容器的效率!
2) 两个引用,如果指向的是同一个对象,则哈希值肯定是一样的!
3) 两个引用,如果指向的是不同对象,则哈希值是不一样的
4) 哈希值主要根据地址号来的!, 不能完全将哈希值等价于地址。
3:toString 方法
- 基本介绍
默认返回:全类名+@+哈希值的十六进制,【查看 Object 的 toString 方法
子类往往重写 toString 方法,用于返回对象的属性信息 - 重写 toString 方法,打印对象或拼接对象时,都会自动调用该对象的 toString 形
- 当直接输出一个对象时,toString 方法会被默认的调用, 比如 System.out.println(monster); 就会默认调用monster.toString()
4:finalize 方法
- 当对象被回收时,系统自动调用该对象的 finalize 方法。子类可以重写该方法,做一些释放资源的操作【演示】
- 什么时候被回收:当某个对象没有任何引用时,则 jvm 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来
销毁该对象,在销毁该对象前,会先调用 finalize 方法。 - 垃圾回收机制的调用,是由系统来决定(即有自己的 GC 算法), 也可以通过 System.gc() 主动触发垃圾回收机制,测
试:Car [name]
提示: 我们在实际开发中,几乎不会运用 finalize , 所以更多就是为了应付面试