文章目录
包
区分相同名字的类,控制访问范围
基本语法: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+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 太慢,我们使用快捷键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"); //创建了子类对象 sub2
System.out.println("===第3对象====");
Sub sub3 = new Sub("king", 10); //创建了子类对象 sub2
//sub.sayOk();
}
}
class TopBase { //父类是Object
public 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的方法,返回了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");}
//父类提供一个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,运行类型是 Cat
Cat 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);// ? 看编译类型 10
Sub 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);// true
System.out.println(bb instanceof AA);// true
//instanceof,判断对象的运行类型是否为XX类型或其子类型
//aa 编译类型 AA, 运行类型是BB
//BB是AA子类
AA aa = new BB();
System.out.println(aa instanceof AA);//true
System.out.println(aa instanceof BB);//true
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 {}//子类
动态绑定机制
public class DynamicBinding {
public static void main(String[] args) {
//a 的编译类型 A, 运行类型 B
A a = new B();//向上转型
System.out.println(a.sum());//30
System.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() {//父类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;
// }
}
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
@Override
protected void finalize() throws Throwable {
System.out.println("我们销毁 汽车" + name );
System.out.println("释放了某些资源...");
}
}