类是抽象的,是一种数据类型 。对象是具体的 对象实现了类的实例化
属性:(又称作成员变量)可以是基础数据变量,也可以是数组或者对象 ,
属性有默认值 例如boolean类型的数据默认为false
方法:将实现的细节封装起来,提高代码的复用性,可以供其他的用户使用
方法重载 -----方法名相同 ,参数列表不同,返回类型无要求
方法重写 ------方法名相同,参数列表相同,返回的类型和父类返回的类型一致,或者是父类 返回类型的 子类型
可变参数 ------ 可变参数本质为数组,和普通的参数放在一起的时候,可变参数放最后,
构造器 --------方法名与类名相同,没有返回值,创建对象时,完成对新对象的初始化
封装是把属性和方法封装在一起,数据被保护在内部,其他程序必须通过被授权的操作,才能对数据进行操作 一般使用属性私有化,然后通过get方法 和set方法来实现封装
继承可以结局代码复用,当多个类存在相同的属性和方法时,可以从这些类中抽象出父类,在父类中定义这些相同 的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可
多态是指一个类中定义的属性和方法被其他类继承后,他们可以具有不同的数据类型或表现出不同的行为,这使得同一个属性和方法在不同的类中具有不同的语义(多态的前提是两个对象存在继承关系)
调用父类的某个构造器:super(参数列表)
调用本类的某个构造器:this(参数列表)
super在使用时,必须放在构造器第一行,因为this()也必须放在第一行,所以super()和this()不能共存一个构造器中
super从父类开始查找属性,从父类查找方法,
调用父类构造器必须必须放在子类构造器首行
this先从本类中查找属性,从本类中查找方法,如果本类中没有属性和方法,再从父类中查找属性和方法 ,但不能访问父类的私有属性和方法 。调用本类构造器,必须放在构造器首行
向上转型:父类的引用指向子类的对象
公式:父类类型引用名 = new 子类类型();
Animal animal =new Cat();
Object obj =new Cat();
向下转型: 父类的引用指向当前目标类型的对象
Cat cat = (Cat)animal
一般会有一个判断条件
if (cat instanceof Animal)
Cat cat =(Cat)animal
判断两个 对象的内容是否相等 如果两个person对象的各个属性值都一样 返回true,否则返回false
class Person{
public String name;
public int age;
public char sex;
//重写Object的equals方法
public boolean equals(Object obj){
//判断如果比较的两个对象是同一个对象,则直接返回true;
if(this == obj){
return true;
}
//类型判断
if(obj instanceof Person){
//如果是Person.我们才比较,不能出现人和小狗比这样的比较
//进行向下转型,因为需要得到obj 的各个属性
Person p =(Person) obj;
return this.name.equals(p.name) && this.age == p.age&& this.sex ==p.sex;}
//如果不是Person.则直接返回false.
return false;
}
返回对象的哈希码值,此方法是为了提高哈希表的性能
没有搞明白
对象被回收时,系统自动调用该对象的finalize方法,子类可以重写该方法,做出释放资源的操作
垃圾回收机制的调用,是由系统来决定,也可以通过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("释放了某些资源...");
}
}
静态成员包括:静态属性和静态方法
1.引入原因:静态变量是同一个类所有对象共享 比如说一个学生拥有一支笔 在定义这个类的时候他就有这只笔了 不管定义的对象是什么学生 都有一只笔
2.特点: static 类变量,在类的加载的时候就生成了 也随着类的消亡而销毁
3.静态属性公式:1.访问修饰符 static 数据类型 变量名;
2.static 访问修饰符 数据类型 变量名
4.静态方法公式:1.访问修饰符 static 数据返回类型 方法名(){}
2.static 访问修饰符 数据返回类型 方法名(){}
5.调用方法:类名.类变量名 类名.类方法名
注意:类方法中不允许使用和对象有关的关键字 比如说this 和super ,并且类方法中只能访问静态变量和静态方法。
引入原因:相当于另外一种构造器 可以做一些初始化操作 。如果多个构造器有重复的语句,可以抽取到初始化块中,提高代码的重用性。
特点:类加载时,或者创建对象时,隐式调用
分类:静态代码块 和普通代码块
静态代码块随着类的加载而执行,并且只会执行一次
普通代码块每创建一个对象,就会执行一次
创建一个类时的调用顺序
父类的静态代码块,静态属性,静态方法
子类的静态代码块,静态属性,静态方法
父类的普通代码块,普通属性,普通方法
父类的构造方法
子类的普通代码块,普通属性,普通方法
子类的构造方法
1)创建对象实例时
2)创建子类对象实例,父类也会被加载
3)使用类的静态成员时
引入原因:
1)当不希望类被继承时,可以使用final关键字
2)当不希望父类的某个方法被子类覆盖/重写时,可以使用fianl关键字修饰
3)当不希望 某个属性值被修改是,可以使用final关键字
4)当不希望某个局部变量被修改,可以使用final修饰
使用方法
1)final修饰的属性又称常量 一般用XX_XX_XX来命名(大写)
2)final修饰的属性在定义时,必须赋初值,并且以后不能修改 ,赋值可以在以下位置之一
1.定义时 2.在构造器中 3.在代码块中
3)如果final修饰的属性是静态的,则初始化的位置只能是
1.定义时 2.在静态代码块 不能在构造器中赋值
4) final类不能继承 但是可以实例化对象
5)如果类不是final类,但是含有final方法,该方法不能被重写,但是可以被继承
6)final不能修饰构造方法
7) final和static往往搭配使用 效率更高,变量成为全局变量
作为父类不知道子类具体的实现的时候,使用一个抽象方法,让子类去实现具体的细节
例如:在父类为animal类,定义一个叫声的抽象方法,子类Cat实现就是喵喵喵,子类Dog实现则为汪汪汪。父类的叫声的抽象方法,子类继承必须要有具体实现
抽象类不能被实例化
抽象类公式: 访问修饰符 abstract 类名
抽象方法公式:访问修饰符 abstract 返回类型 方法名 (参数列表);//没有方法体
抽象类的价值更多在于设计:让子类继承并实现抽象类
abstract只能修饰类和方法 ,不能修饰属性和其他的
抽象方法不能被private ,final 和static修饰
抽象类不一定要包含抽象方法,但是包含抽象方法一定是抽象类,一个类继承了抽象类,必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类(重点)
package Abstract;
public class abstract_ {
}
abstract class Animal{
private String name;
public Animal(String name) {
this.name = name;
}
//思考:这里的eat方法没有意义,即父类方法不确定性问题
// 可以将该方法设计为抽象方法
//所谓抽象方法就是没有实现的方法,即没有方法体
// 当一个类有abstract方法时,应该声明该类是abstract类,
public abstract void eat();
}
接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来
比如:你可以把手机,相机,U盘都插在usb插槽上,而不用担心那个插槽是专门插哪一个的,原因是做usb插槽的参加和做各种设备的厂家都遵守了统一的规定包括尺寸,盘线等
interface 接口名{
//属性
//方法(1.抽象方法 2,默认实现方法 3,静态方法)
}
class 类名 implements 接口{
自己的属性
自己的方法
必须实现的接口的接口方法
}
1.接口不能被实例化,一个类可以实现多个接口
2.接口中所有方法是public方法 ,接口中抽象方法,可以不用abstract去修饰
3.接口中的默认属性修饰符为 public static final
4. 抽象类实现接口可以不用实现接口方法,普通类实现接口必须实现接口的所有方法
5.接口中的属性的访问形式:接口名.属性名
6.接口不能结城其他的类,但是可以继承多个别的接口
7.接口的修饰符只能是public 和默认 这点和类的修饰符是一样的
继承的价值主要在于:解决代码的复用性和可维护性
接口的价值主要在于:设计,设计好各种规范,让其他类去实现这些方法。
接口比继承更加灵活,继承是is -a的关系 而接口只需满足like -a的关系
package com.hspedu.interface_;
public interface DBInterface { //项目经理
public void connect();//连接方法
public void close();//关闭连接
}
package com.hspedu.interface_;
//A 程序
public class MysqlDB implements DBInterface {
@Override
public void connect() {
System.out.println("连接 mysql");
}
@Override
public void close() {
System.out.println("关闭 mysql");
}
}
package com.hspedu.interface_;
//B 程序员连接 Oracle
public class OracleDB implements DBInterface{
@Override
public void connect() {
System.out.println("连接 oracle");
}
@Override
public void close() {
System.out.println("关闭 oracle");
}
}
package com.hspedu.interface_;
public class Interface03 {
public static void main(String[] args) {
MysqlDB mysqlDB = new MysqlDB();
t(mysqlDB);
OracleDB oracleDB = new OracleDB();
t(oracleDB);
}
public static void t(DBInterface db) {
db.connect();
db.close();
}
}
package com.hspedu.interface_;
public class InterfacePolyArr {
public static void main(String[] args) {
//多态数组 -> 接口类型数组
Usb[] usbs = new Usb[2];
usbs[0] = new Phone_();
usbs[1] = new Camera_();
/*给 Usb 数组中,存放 Phone 和 相机对象,Phone 类还有一个特有的方法 call(),
请遍历 Usb 数组,如果是 Phone 对象,除了调用 Usb 接口定义的方法外,
还需要调用 Phone 特有方法 call */
for(int i = 0; i < usbs.length; i++) {
usbs[i].work();//动态绑定..
//和前面一样,我们仍然需要进行类型的向下转型
if(usbs[i] instanceof Phone_) {//判断他的运行类型是 Phone_
((Phone_) usbs[i]).call();
}
}
}
}
interface Usb{
void work();
}
class Phone_ implements Usb {
public void call() {
System.out.println("手机可以打电话...");
}
@Override public void work() {
System.out.println("手机工作中...");
}
}
class Camera_ implements Usb {
@Override
public void work() {
System.out.println("相机工作中...");
}
}
1.在前面的usb接口案例中,UsbInterface usb,即可以接收手机对象,又可以接收相机对象 ,体现了类接口的多态
2.多态传递现象:如果ig继承了ih接口,而teacher类实现了ig接口,那么相当于teacher类实现了ih接口,这就是所谓的接口多态传递现象。
3.多态数组问题
例题
package com.hspedu.interface_;
public class InterfacePolyParameter {
public static void main(String[] args) {
//接口的多态体现
//接口类型的变量 if01 可以指向 实现了 IF 接口类的对象实例
IF if01 = new Monster();
if01 = new Car();
//继承体现的多态
//父类类型的变量 a 可以指向 继承 AAA 的子类的对象实例
AAA a = new BBB();
a = new CCC();
}
}
interface IF {}
class Monster implements IF{}
class Car implements IF{}
class AAA { }
class BBB extends AAA {}
class CCC extends AAA {}
package com.hspedu.interface_;
public class InterfacePolyPass {
public static void main(String[] args) {
//接口类型的变量可以指向,实现了该接口的类的对象实例
IG ig = new Teacher();
//如果 IG 继承了 IH 接口,而 Teacher 类实现了 IG 接口
//那么,实际上就相当于 Teacher 类也实现了 IH 接口.
//这就是所谓的 接口多态传递现象.
IH ih = new Teacher();
}
}
interface IH {
void hi();
}
interface IG extends IH{ }
class Teacher implements IG {
@Override
public void hi() {
}
}
package com.hspedu.interface_;
public class InterfacePolyArr {
public static void main(String[] args) {
//多态数组 -> 接口类型数组
Usb[] usbs = new Usb[2];
usbs[0] = new Phone_();
usbs[1] = new Camera_();
/*给 Usb 数组中,存放 Phone 和 相机对象,Phone 类还有一个特有的方法 call(),
请遍历 Usb 数组,如果是 Phone 对象,除了调用 Usb 接口定义的方法外,
还需要调用 Phone 特有方法 call */
for(int i = 0; i < usbs.length; i++) {
usbs[i].work();//动态绑定..
//和前面一样,我们仍然需要进行类型的向下转型
if(usbs[i] instanceof Phone_) {//判断他的运行类型是 Phone_
((Phone_) usbs[i]).call();
}
}
}
}
interface Usb{
void work();
}
class Phone_ implements Usb {
public void call() {
System.out.println("手机可以打电话...");
}
@Override public void work() {
System.out.println("手机工作中...");
}
}
class Camera_ implements Usb {
@Override
public void work() {
System.out.println("相机工作中...");
}
}
内部类可以直接访问私有属性 ,并且可以体现类与类之间的包含关系
class Outer{// 外部类
class Inner{//内部类
}
}
class Other{//外部其他类
}
定义在外部类的局部位置上 (比如方法体内)
1)局部内部类(有类名)
2)匿名内部类(没有类名)
定义在外部类的成员位置上
1)成员内部类(不用static修饰)
2)静态内部类(使用static修饰)
局部内部类和匿名内部类定义在外部类的局部位置,比如方法体中,局部内部有类名,匿名内部类没有 成员内部类 定义在外部类的成员位置,没有static修饰,有static修饰的为静态内部类
1.四个内部类都可以直接访问外部类的所有成员,包括私有的 但是静态内部类只能访问静态 成员
2.局部内部类和匿名内部类不能添加访问修饰符,因为它们的地位是一个局部变量,但是可 以使用final修饰。成员内部类和静态内部类可以添加修饰符,因为它们的地位就是一个成员
3.作用域:局部内部类和匿名内部类仅仅在定义它的方法或代码块中
成员内部类和静态内部类和外部类其他成员一样,为整个类
4.局部内部类 ==》直接访问==》外部类成员
匿名内部类 ==》直接访问==》外部类成员
成员内部类==》直接访问==》外部类成员
静态内部类 ==》访问==》外部类的静态成员
5.外部类可以访问局部内部类,成员内部类 和静态内部类 成员 访问方式 :首先创建对象, 再访问。但是外部类不能访问匿名内部类
6.外部其他类不能访问匿名内部类和局部内部类 ,但是可以访问静态内部类和成员内部类
7.如果外部类和局部内部类,成员内部类,静态内部类或者匿名内部类的成员重名时,默认 遵循就近原则,如果想访问外部类的成员,静态内部类可以使用外部类名.成员。其他内 部类则可以使用外部类名.this.成员去访问 。
例如:System.out.println("外部类的n2 = "+ 外部类名.this.n2);
8.匿名内部类的语法比较奇特,因为匿名内部类即是一个类的定义,同时它本身也是一个对 象,因此从语法上来看,他既有定义类的特征,也有创建对象的特征,对前面代码分析可 以看出这个特点,因此可以调用匿名内部类方法
(如果第一道题都看不下去 那你别学了)
package Innerclass;
//演示局部内部类的使用
public class LocalInnerClass {
public static void main(String[] args) {
Outer02 P1 = new Outer02();
P1.m1();//创建Outer方法,调用有内部类的方法,
// 然后再从方法中创建对象,调用内部类中的成员
}
}
class Outer02{
private int n1=100;
public void m1(){
//局部内部类是定义在外部类的局部位置,通常在方法
class Inner02{//(局部内部类本质是一个类)
//不能用访问修饰符去修饰,但是可以被final修饰
//可以直接访问外部类的所有成员,包含私有的
private int n1 =500;
public void f1(){
System.out.println("n1= "+n1);// n1=500
//m1();
//局部内部类与外部类的成员方法名相同
//利用就近原则访问局部内部类
//利用外部类名.this.成员方法名的方式访问外部类
System.out.println(n1);//500
System.out.println(Outer02.this.n1);//100
}
}
Inner02 inner02 = new Inner02();
inner02.f1();//创建对象调用方法,可以访问到内部类成员
}
}
1.这道题涉及到
匿名内部类的源码 (建议反复观看)
package com.hspedu.innerclass;
/**
* 演示匿名内部类的使用
*/
public class AnonymousInnerClass {
public static void main(String[] args) {
Outer04 outer04 = new Outer04();
outer04.method();
}
}
class Outer04 { //外部类
private int n1 = 10;//属性
public void method() {//方法
//基于接口的匿名内部类
//1.需求: 想使用 IA 接口,并创建对象
//2.传统方式,是写一个类,实现该接口,并创建对象
//3.老韩需求是 Tiger/Dog 类只是使用一次,后面再不使用
//4. 可以使用匿名内部类来简化开发
//5. tiger 的编译类型 ? IA
//6. tiger 的运行类型 ? 就是匿名内部类 Outer04$1
/*
我们看底层 会分配 类名 Outer04$1
class Outer04$1 implements IA {
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
}
*/
//7. jdk 底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1 实例,并且把地址
// 返回给 tiger
//8. 匿名内部类使用一次,就不能再使用
IA tiger = new IA() {
@Override
public void cry() {
System.out.println("老虎叫唤...");
}
};
System.out.println("tiger 的运行类型=" + tiger.getClass());
tiger.cry();
tiger.cry();
tiger.cry(); //实例用多少次都行,但匿名内部类只能使用一次
// IA tiger = new Tiger();
// tiger.cry();
//演示基于类的匿名内部类
//分析
//1. father 编译类型 Father
//2. father 运行类型 Outer04$2
//3. 底层会创建匿名内部类
/*
class Outer04$2 extends Father{
@Override
public void test() {
System.out.println("匿名内部类重写了 test 方法");
}
}
*/
//4. 同时也直接返回了 匿名内部类 Outer04$2 的对象
//5. 注意("jack") 参数列表会传递给 构造器
Father father = new Father("jack"){
@Override
public void test() {
System.out.println("匿名内部类重写了 test 方法");
}
}; //如果把方法体去掉,则运行类型为father
System.out.println("father 对象的运行类型=" + father.getClass());//Outer04$2
father.test();
//基于抽象类的匿名内部类
Animal animal = new Animal(){
@Override
void eat() {
System.out.println("小狗吃骨头...");
}
};
animal.eat();
}
}
interface IA {//接口
public void cry();
}
class Father {//类
public Father(String name) {//构造器
System.out.println("接收到 name=" + name);
}
public void test() {//方法
}
}
abstract class Animal { //抽象类
abstract void eat();
}
2.匿名内部类的第二道例题
package com.hspedu.innerclass;
public class InnerClassExercise02 {
public static void main(String[] args) {
CellPhone cellPhone = new CellPhone();
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("懒猪起床了");
}
});
cellPhone.alarmClock(new Bell() {
@Override
public void ring() {
System.out.println("小伙伴上课了");
}
});
}
}
interface Bell{ //接口
void ring();//方法
}
class CellPhone{//类
public void alarmClock(Bell bell){//形参是 Bell 接口类型
System.out.println(bell.getClass());
bell.ring();//动态绑定
}
}
(或许看到这就感觉到枯燥 乏味,但是只剩下两道例题了,加油)
package com.hspedu.innerclass;
public class MemberInnerClass01 {
public static void main(String[] args) {
Outer08 outer08 = new Outer08();
outer08.t1();
//外部其他类,使用成员内部类的三种方式
// 第一种方式
// outer08.new Inner08(); 相当于把 new Inner08()当做是 outer08 成员
// 这就是一个语法,不要特别的纠结.
Outer08.Inner08 inner08 = outer08.new Inner08();
inner08.say();
// 第二方式 在外部类中,编写一个方法,可以返回 Inner08 对象
Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
inner08Instance.say();
}
}
class Outer08 { //外部类
private int n1 = 10;
public String name = "张三";
private void hi() {
System.out.println("hi()方法...");
}
//1.注意: 成员内部类,是定义在外部内的成员位置上
//2.可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员
public class Inner08 {//成员内部类
private double sal = 99.8;
private int n1 = 66;
public void say() {
//可以直接访问外部类的所有成员,包含私有的
//如果成员内部类的成员和外部类的成员重名,会遵守就近原则.
//可以通过 外部类名.this.属性 来访问外部类的成员
System.out.println("n1 = " + n1 + " name = " + name + " 外部类的 n1=" + Outer08.this.n1);
hi();
}
}
//第二种方法,返回一个 Inner08 实例
public Inner08 getInner08Instance(){
return new Inner08();
}
//写方法
public void t1() {
//使用成员内部类
//创建成员内部类的对象,然后使用相关的方法
Inner08 inner08 = new Inner08();
inner08.say();
System.out.println(inner08.sal);
}
}
(最后一题 ,马上就要成功了)
package Innerclass;
public class StaticInnerClass {
public static void main(String[] args) {
Li li = new Li();
li.setbus();
//外部其他类访问内部类方法
//第一种方式,直接创建静态内部类的对象
Li.bus b1 = new Li.bus();
b1.r2();
//第二种方式,调用普通成员方法返回静态内部类
Li.bus b2 = li.getbus();
System.out.println(b2.r1);
//第三种方式,调用静态成员返回静态内部类
Li.bus b3 = Li.getbus_();
b3.r2();
}
}
class Li{
public static int num =888;
public int t1 = 99;
public void hello(){
System.out.println("你好");
}
public static class bus{
public int r1=55;
public void r2(){
System.out.println("num = "+num);
// System.out.println("y1= "y1);//不可以访问非静态成员
}
}
public void setbus(){//外部类访问内部类方法
bus u1 = new bus();
System.out.println(u1.r1);
u1.r2();
}
public bus getbus(){//其他类访问内部类方法2
return new bus();
}
public static bus getbus_(){//其他类访问内部类方法3
return new bus();
}
}