1. 初认识

1.1 类和对象

在计算机的世界中,我们经常需要去描述现实中存在的物体,例如:动物、手机、水果、汽车……,这些事物往往存在着诸多复杂的功能和属性,这时候,我们就可以利用类和对象的思想在计算机中进一步描述他们

1.1.1 什么是类?什么是对象?

  • 现实生活是由很多很多对象组成的,基于对象抽出了类
  • 对象:软件中真实存在的单个的个体/东西
    类:类型/类别,代表一类个体
  • 类是对象的模板/模子,对象是类的具体的实例
  • 类中可以包含:
    • 对象的属性/特征/数据-----------------------成员变量
    • 对象的行为/动作/功能-----------------------方法
  • 一个类可以创建多个对象
  • 三大特性:封装、继承、多态

1.1.2 如何创建类?如何创建对象?如何访问成员?

public class Student {//成员变量String name;int age;String address;//方法void study(){System.out.println(name+"在学习...");}void sayHi(){System.out.println("大家好,我叫"+name+",今年"+age+"岁了,家住"+address);}
}
public class StudentTest {public static void main(String[] args) {//创建一个学生对象Student zs = new Student();//访问成员变量zs.name = "zhangsan";zs.age = 25;zs.address = "河北廊坊";//调用方法zs.study();zs.sayHi();Student ls = new Student();ls.name = "lisi";ls.age = 24;ls.address = "黑龙江佳木斯";ls.study();ls.sayHi();//1)创建了一个Student对象//2)给成员变量赋默认值Student ww = new Student();ww.study();ww.sayHi();}
}

补充:

  1. 类:是一种引用数据类型
  2. 创建对象:
          引用
数据类型 引用类型变量  指向      对象
Student    zs        =   new Student(); //创建一个Student型的引用zs,指向了一个学生对象//zs代表的就是那个学生对象,用zs就是在用那个对象
  1. 引用类型的默认值为:null

2. 面向对象相关的各类语法

2.1 构造方法

构造方法:------------------------------------复用给成员变量赋初值的代码

  • 作用:给成员变量赋初始值
  • 语法:与类同名,没有返回值类型(连void都没有)
  • 调用:在创建(new)对象时被自动调用
  • 若自己不写构造方法,则编译器默认提供一个无参的构造方法,若自己写了构造方法,则不再默认提供
  • 构造方法可以重载
package day006;public class Test2_构造方法 {String name;//当存在一个含参的构造方法时,无参构造将不再自动生成...    //public Test2_构造方法(){}//含参构造public Test2_构造方法(String n){name=n;}void eat(){System.out.println("Test2_构造方法.eat()");}
}class tt{public static void main(String[] args) {//注释掉无参的构造也可以运行,说明系统会自动提供一个无参的构造方法Test2_构造方法 t2 = new Test2_构造方法();t2.eat(); //t是引用变量,引用的是对象的地址值。//根据地址值找到对象,并获取对象的数据Test2_构造方法 t = new Test2_构造方法("张三");System.out.println(t.name);}
}

2.2 话题:内存管理

内存管理:由JVM来管理的

  • 堆:new出来的对象(包括成员变量、数组的元素)
  • 栈:局部变量(包括方法的参数)
  • 方法区:存储.class字节码文件(包括静态变量、所有方法)

补充:
若变量为基本数据类型,则装的是具体的数
若变量为引用数据类型,则装的是堆中对象的地址

2.2.1 单一对象内存图

过程说明:
Person p = new Person();

Person p = new Person();//短短这行代码发生了很多事情
1.把Person.class文件加载进内存
2.在栈内存中,开辟空间,存放引用变量p
3.在堆内存中,开辟空间,存放Person对象
4.对成员变量进行默认的初始化
5.对成员变量进行显示初始化
6.执行构造方法(如果有构造代码块,就先执行构造代码块再执行构造方法)
7.堆内存完成
8.把堆内存的地址值赋值给变量p ,p就是一个引用变量,引用了Person对象的地址值

2.2.2 多对象内存图

  1. 变量p和变量p1不是一片空间,p1需要开辟新的空间
  2. Person p1=new Person,这时只要有new,就会新开辟空间在堆内存中存入对象。
package day000000;public class Test1 {public static void main(String[] args) {//p是引用对象,持有了对于Person对象的地址值的引用//此时的p,含有属性,但都是默认值Person p = new Person();//设置属性值p.name="lisi";p.age=20;//创建p2Person p2=new Person();p2.name="zhangsan";p2.age=10;}
}class Person{//属性--成员变量String name;int age;//行为--方法void eat(){System.out.println("吃饭饭");}void sleep(){System.out.println("睡觉觉");}
}

2.2.3 static的内存图

补充:
成员变量分两种:

  • 实例变量:没有static修饰,属于对象的,存储在堆中,有几个对象就有几份,通过引用名(对象)打点来访问
  • 静态变量:有static修饰,属于类的,存储在方法区中,只有一份,通过类名打点来访问

2.2.4 null的内存图

null:表示空,没有指向任何对象

  • 若引用的值为null,则该引用不能再进行任何操作了,若操作则发生NullPointerException空指针异常
//演示
Student s = new Student();
s = null;
s.name = "纳西妲";//运行时错误,发生NullPointerException空指针异常

2.3 三大特性------继承

说明:

  1. 继承是面向对象最显著的一个特性。
  2. 继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
  3. Java继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类/超类/基类。
  4. 这种技术使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用。
  5. 提高复用性:只要继承父类,就能有一样的功能
    ===============================================
  • 作用:代码复用
  • 通过extends实现继承
  • 超类/父类:共有的属性和行为 派生类/子类:特有的属性和行为
  • 派生类可以访问派生类的+超类的,但超类不能访问派生类的
  • 一个超类可以有多个派生类,但一个派生类只能有一个超类------------单一继承
  • 继承具有传递性
  • 继承要符合is(是)的关系

入门案例:

package day99999;public class TTT {public static void main(String[] args) {Zi zi = new Zi();zi.speak();System.out.println(zi.skin);System.out.println(zi.addr);}
}class Fu{String skin="黄种人";String addr="大成都";public void speak(){System.out.println("Fu...speak()");}}//通过extends和父类发生继承关系
//所有父类的功能,子类都可以继承过来,注意不能是private的
class Zi extends Fu{//什么都不写,能不能把父亲的内容复制一份出来
}

补充:
继承的好处:

  • 封装共有的属性和行为---------------实现代码复用
  • 为所有派生类提供统一的类型------向上造型(实现代码复用)

2.3.1 关键字 super

super:指代当前对象的超类对象
super的用法:

  • super.成员变量名-------------------访问超类的成员变量(一般都省略,了解即可)

  • super.方法名()-----------------------调用超类的方法(一般重写发生时,调用超类方法使用)

  • super()---------------------------------调用超类的构造方法

  • java规定:构造派生类之前必须构造超类

    • 在派生类的构造方法中若没有调用超类的构造方法,则默认super()调超类无参构造
    • 在派生类的构造方法中若自己调用了超类的构造方法,则不再默认提供

注意:super调超类构造方法必须位于派生类构造方法的第一行(保证先父再子)

入门案例:

public class SuperDemo {public static void main(String[] args) {Boo o = new Boo();}
}//在派生类的构造方法中若自己调用了超类的构造方法,则不再默认提供
class Coo{Coo(int a){}
}
class Doo extends Coo{Doo(){super(5);}/*//如下一堆为默认的Doo(){super();}*/
}class Aoo{Aoo(){System.out.println("超类构造方法");}
}
//在派生类的构造方法中若没有调用超类的构造方法,则默认super()调超类无参构造
class Boo extends Aoo{Boo(){super(); //默认的,调用超类的构造方法System.out.println("派生类构造方法");}
}

2.4 三大特性------多态

1、 多态的前提是继承
2、 要有方法的重写
3、 父类引用指向子类对象,如:Animal a = new Dog(); -- 小到大,向上转型
4、 多态中,编译看左边,运行看右边
5、 多态的好处:

  1. 多态可以让我们不用关心某个对象到底具体是什么类型,就可以使用该对象的某些方法
  2. 提高了程序的可扩展性和可维护性

1)入门案例:

public class UploadDemo {public static void main(String[] args) {Eoo o1 = new Eoo();o1.a = 1;o1.show();//o1.b = 2;  //编译错误//o1.test(); //编译错误,超类不能访问派生类的Foo o2 = new Foo();o2.b = 1;o2.test();o2.a = 2;  //正确o2.show(); //正确,派生类可以访问超类的Eoo o3 = new Foo(); //向上造型o3.a = 1;o3.show();//o3.b = 2;  //编译错误//o3.test(); //编译错误,能点出来什么,看引用的类型}
}class Eoo{int a;void show(){}
}
class Foo extends Eoo{int b;void test(){}
}

2)多态的使用

前提:多态对象把自己看做是父类类型

  • 成员变量: 使用的是父类的
  • 成员方法: 由于存在重写现象,所以使用的是子类的
  • 静态成员: 随着类的加载而加载,谁调用就返回谁的
package cn.tedu.oop2;
/*本类用于测试多态成员的使用情况*/
public class TestDemo2 {public static void main(String[] args) {//7.创建纯纯的子类对象Dog2 d = new Dog2();System.out.println(d.sum);//20,子类自己的属性d.eat();//小狗爱吃肉包子,子类自己的方法//8.创建多态对象/*口诀1:父类引用指向子类对象*//*口诀2:编译(保存)看左边,运行(效果)看右边*/Animal2 a = new Dog2();/*多态中,成员变量使用的是父类的*/System.out.println(a.sum);//10/*多态中,方法的声明使用的是父类的,方法体使用的是子类的*/a.eat();//小狗爱吃肉包子/*多态中,调用的静态方法是父类的,因为多态对象把自己看作是父类类型* 直接使用父类中的静态资源*/a.play();//没有提示,玩啥都行~Animal2.play();}
}
//1.创建父类
class Animal2{//3.创建父类的成员变量int sum = 10;//4.创建父类的普通方法public void eat(){System.out.println("吃啥都行~");}//9.1定义父类的静态方法playpublic static void play(){System.out.println("玩啥都行~");}
}
//2.创建子类
class Dog2 extends Animal2{//5.定义子类的成员变量int sum = 20;//6.重写父类的方法@Overridepublic void eat(){System.out.println("小狗爱吃肉包子");}//9.2创建子类的静态方法play//@Override/*这不是一个重写的方法,只是恰巧在两个类中出现了一模一样的两个静态方法* 静态方法属于类资源,只有一份,不存在重写的现象* 在哪个类里定义,就作为哪个类的资源使用*/public static void play(){System.out.println("小狗喜欢玩皮球~");}
}

3)多态为了统一调用标准

package cn.tedu.oop2;public class TestFruit {public static void main(String[] args) {Fruit f = new Fruit();Apple a = new Apple();Orange o = new Orange();get(f);get(a);get(o);}//只需要创建一个方法,就可以执行截然不同的效果//忽略子类对象的差异统一看作父类类型public static void get(Fruit f){f.clean();}
}
class Fruit{public void clean(){System.out.println("水果要洗洗再吃");}
}
class Apple extends Fruit{@Overridepublic void clean(){System.out.println("苹果需要削皮");}
}
class Orange extends Fruit{@Overridepublic void clean(){System.out.println("橙子需要剥皮");}
}

2.4.1 向上转型和向下转型

在JAVA中,继承是一个重要的特征,通过extends关键字,子类可以复用父类的功能,如果父类不能满足当前子类的需求,则子类可以重写父类中的方法来加以扩展。
          那么在这个过程中就存在着多态的应用。存在着两种转型方式,分别是:向上转型和向下转型

  1. 向上转型:可以把不同的子类对象都当作父类来看,进而屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。
    比如:父类Parent,子类Child
    父类的引用指向子类对象:Parent p=new Child();
    说明:向上转型时,子类对象当成父类对象,只能调用父类的功能,如果子类重写了父类中声明过的方法,方法体执行的就是子类重过后的功能。但是此时对象是把自己看做是父类类型的,所以其他资源使用的还是父类型的。
    比如:花木兰替父从军,大家都把花木兰看做她爸,但是实际从军的是花木兰,而且,花木兰只能做她爸能做的事,在军营里是不可以化妆的。
  2. 向下转型(较少):子类的引用的指向子类对象,过程中必须要采取到强制转型。这个是之前向上造型过的子类对象仍然想执行子类的特有功能,所以需要重新恢复成子类对象
    Parent p = new Child();//向上转型,此时,p是Parent类型
    Child c = (Child)p;//此时,把Parent类型的p转成小类型Child
    其实,相当于创建了一个子类对象一样,可以用父类的,也可以用自己的
    说明:向下转型时,是为了方便使用子类的特殊方法,也就是说当子类方法做了功能拓展,就可以直接使用子类功能。
    比如:花木兰打仗结束,就不需要再看做是她爸了,就可以”对镜贴花黄”了

2.5 三大特性------封装

概述:
封装是指隐藏对象的属性和实现细节,仅仅对外提供公共的访问方式。

好处:

1、 提高安全性

2、 提高重用性

2.5.1 关键字private

是一个权限修饰符,用于修饰成员变量和成员函数,被私有化的成员只能在本类中访问。
想要修改只能,对外提供公共的,get和set方法。
一般情况下:数据(成员变量)私有化(private),行为(方法)大部分都公开化(public)

package day006;public class Student {//String name;//把属性隐藏起来private String name;//提供公共的访问方法//设置公共的赋值方法public void setName(String n){name=n;}//设置公共的取值方法public String getName(){return name;}     int age;
}class StDemo{public static void main(String[] args) {Student s = new Student();//不能访问私有的//s.name="zhangsan";//System.out.println(s.name);s//利用setXxx()给属性赋值s.setName("zhangsan");//利用getXxx()给属性取值System.out.println(s.getName());}
}

2.6 面向对象知识补充

2.6.1 package和import

  • package:声明包

    • 作用:避免类的命名冲突
    • 规定:同包中的类不能同名,但不同包中的类可以同名
    • 类的全称:包名.类名
    • 建议:包名所有字母都小写,并且常常有层次结构
  • import:导入类
    • 同包中的类可以直接访问,但不同包中的类不能直接访问,若想访问:

      • 先import导入类,再访问类-------------建议
      • 类的全称--------------------------------------太繁琐,不建议

2.6.2 访问控制修饰符

作用:保护数据的安全,实现封装,隐藏数据,暴露行为

  • public:公开的,任何类
  • private:私有的,本类
  • protected:受保护的,本类、派生类、同包类
  • 默认的:什么也不写,本类、同包类--------java不建议默认权限 注意:
    1. 类的访问权限只能是public或默认的
    2. 类中成员的访问权限如上4种都可以
    3. 访问控制修饰符的访问权限由高到低依次为:public>protected>默认的>private

package ooday05;
public class Aoo {public int a;    //任何类protected int b; //本类、派生类、同包类int c;           //本类、同包类private int d;   //本类void show(){a = 1;b = 2;c = 3;d = 4;}
}class Boo{ //----------------------演示privatevoid show(){Aoo o = new Aoo();o.a = 1;o.b = 2;o.c = 3;//o.d = 4; //编译错误}
}package ooday05_vis;
import ooday05.Aoo;public class Coo { //----------------------演示同包的void show(){Aoo o = new Aoo();o.a = 1;//o.b = 2; //编译错误//o.c = 3; //编译错误//o.d = 4; //编译错误}
}class Doo extends Aoo{ //跨包继承-----------演示protectedvoid show(){a = 1;b = 2;//c = 3; //编译错误//d = 4; //编译错误}
}

2.6.3 final关键字

概念:
1、 是java提供的一个关键字

2、 final是最终的意思

3、 final可以修饰类,方法,成员变量

初衷是因为:java出现了继承后,子类可以更改父类的功能,当父类功能不许子类改变时可以利用final关键字修饰父类。
 
特点:
1、 被final修饰的类,不能被继承

2、 被final修饰的方法,不能被重写

3、 被final修饰的变量是个常量,值不能被更改

4、 常量的定义形式: final 数据类型 常量名 = 值

  • 修饰变量:变量不能被改变
class Eoo{final int a = 5;int b = 6;void test(){//a = 55; //编译错误,final的变量不能被改变b = 66;}
}
  • 修饰方法:方法不能被重写
class Foo{final void show(){}void test(){}
}
class Goo extends Foo{//void show(){} //编译错误,final的方法不能被重写void test(){}
}
  • 修饰类:类不能被继承
final class Hoo{}
//class Ioo extends Hoo{} //编译错误,final的类不能被继承
class Joo{}
final class Koo extends Joo{} //正确,不能当老爸,但能当儿子

2.6.4 static关键字

概念
1、 是java中的一个关键字

2、 用于修饰成员(成员变量和成员方法)
 
特点
1、 可以修饰成员变量,成员方法

2、 随着类的加载而加载,优先于对象加载

3、 只加载一次,就会一直存在,不再开辟新空间

4、 全局唯一,全局共享

5、 可以直接被类名调用

6、 静态只能调用静态,非静态可以随意调用

7、 static不能和this或者super共用,因为有static时可能还没有对象
8、属于类,存储在方法区中,只有一份
9、静态方法中没有隐式this传递,所以不能直接访问实例成员

1)入门案例:

package cn.tedu.oop;
/*本类用作静态static的入门案例*/
/*0.被static修饰的资源统称为静态资源
* 静态资源是随着类加载而加载到内存中的,比对象优先进入内存
* 所以静态资源可以不通过对象,直接通过类名调用*/
public class TestStatic1 {public static void main(String[] args) {//5.通过类名直接调用静态资源Fruit.clean();//我们可以通过类名直接调用静态方法,这个IDEA会提示System.out.println(Fruit.kind);//我们可以通过类名直接调用静态属性,这个IDEA会提示//4.创建水果类的对象Fruit f1 = new Fruit();Fruit f2 = new Fruit();f1.grow();f1.clean();//没有提示,需要自己写System.out.println(f1.weight);System.out.println(f1.kind);//没有提示,需要自己写//6.修改普通变量的值f1.weight = 6.6;System.out.println(f1.weight);//6.6System.out.println(f2.weight);//0.0/*3.静态资源在内存中只有一份,而且会被全局所有对象共享* 所以:不管我们使用哪种方式修改了静态变量的值,使用任何方式来查看* 都是静态变量那个刚刚修改了的值*///7.修改静态变量的值Fruit.kind = "苹果";System.out.println(Fruit.kind);System.out.println(f1.kind);System.out.println(f2.kind);f1.kind = "猕猴桃";System.out.println(Fruit.kind);System.out.println(f1.kind);System.out.println(f2.kind);f2.kind = "香蕉";System.out.println(Fruit.kind);System.out.println(f1.kind);System.out.println(f2.kind);}
}//1.创建水果类
class Fruit{//2.定义属性/*1.可以用static修饰成员变量吗?--可以*/static String kind;//品种double weight;//重量//3.定义方法/*2.可以用static修饰方法吗?--可以*/public static void clean(){System.out.println("洗水果呀洗水果~");}public void grow(){System.out.println("这个果子长的一看就很好吃~");}
}

2)static静态调用关系:

package cn.tedu.oopstatic;
/*本类用于测试静态的调用关系*/
/*总结:
* 1.普通资源既可以调用普通资源,也可以调用静态资源
* 2.静态资源只能调用静态资源*/
public class TestStatic2 {}
//1.创建老师类
class Teacher{//2.定义普通属性与方法String name;public void teach(){System.out.println("正在授课中...");/*1.普通资源能否调用静态资源?--可以!!!*/System.out.println(age);ready();}//3.定义静态属性与方法static int age;public static void ready(){System.out.println("正在备课中...");/*2.静态资源能否调用普通资源?--不可以!*///System.out.println(name);//teach();}public static void eat(){System.out.println("正在吃饭中...");/*3.静态资源能否调用静态资源?--可以!*/System.out.println(age);ready();}
}

2.6.5 代码块

2.6.5.1 构造代码块与局部代码块

形式:{ 代码… }

  1. 构造代码块:
    位置: 在类的内部,在方法的外部
    作用: 用于抽取构造方法中的共性代码
    执行时机: 每次调用构造方法前都会调用构造代码块
    注意事项: 构造代码块优先于构造方法加载
  2. 局部代码块
    位置: 在方法里面的代码块
    作用: 通常用于控制变量的作用范围,出了花括号就失效
    注意事项: 变量的作用范围越小越好,成员变量会存在线程安全的问题

测试代码块的加载顺序:

package cn.tedu.oop;
/*本类用于测试代码块
执行顺序:构造代码块->构造方法->普通方法->局部代码块,分析:
1.当创建对象时,会触发构造函数
2.创建对象时,也会触发构造代码块,并且构造代码块优先于构造方法执行
3.我们创建好对象后才能通过对象调用普通方法
4.如果普通方法里有局部代码块,才会触发对应的局部代码块 */
public class TestBlock {public static void main(String[] args) {//5.分别触发3个构造函数创建对象Pig p1 = new Pig();//触发的是无参构造Pig p2 = new Pig("佩奇");//触发的是含参构造Pig p3 = new Pig("肉包子",5);//触发的是全参构造//6.通过创建好的对象进行测试System.out.println(p1.age);//0,默认值System.out.println(p2.age);//0,默认值System.out.println(p3.age);//5,创建对象时赋值的p1.eat();p2.eat();p3.eat();}
}
//1.创建一个小猪类用来测试
class Pig{//2.定义属性String food;//食物int age;//年龄//7.创建本类的构造代码块{/*构造代码块:{}* 1.位置:类里方法外* 2.执行时机:每次创建对象时都会执行构造代码块,并且构造代码块优先于构造方法执行* 3.作用:用于提取所有构造方法的共性功能*/System.out.println("我是一个构造代码块");System.out.println("黑猪肉!");}//4.1创建本类的无参构造public Pig(){//System.out.println("黑猪肉~");System.out.println("我是Pig类的无参构造");}//4.2创建本类的含参构造public Pig(String s){//System.out.println("黑猪肉~");System.out.println("我是Pig类的含参构造"+s);}//4.3创建本类的全参构造//右键->Generate->Constructor->Shift全选所有属性->okpublic Pig(String food, int age) {//System.out.println("黑猪肉~");System.out.println("我是Pig类的全参构造");this.food = food;this.age = age;}//3.创建普通方法public void eat(){System.out.println("小猪爱吃菜叶子");//8.创建本类的局部代码块{/*局部代码块:{}1.位置:方法里2.执行时机:调用本局部代码块所处的方法时才会执行3.作用:用于控制变量的作用范围,变量的作用范围越小越好* */System.out.println("我是一个局部代码块");int i = 100;System.out.println(i);}//System.out.println(i);//局部代码块中的局部变量i只能在代码块里使用}
}

2.6.5.2 静态代码块

形式:static{}
静态资源随着类的加载而加载,并且只被加载一次,一般用于项目的初始化
特点: 被static修饰,位置在类里方法外

class Poo{static{System.out.println("静态块");}Poo(){System.out.println("构造方法");}
}
public class StaticDemo {public static void main(String[] args) {Poo p1 = new Poo();Poo p2 = new Poo();Poo p3 = new Poo();}
}

2.6.5.3 三种代码块的比较

静态代码块:在类加载时就加载,并且只被加载一次,一般用于项目的初始化
构造代码块:在创建对象时会自动调用,每次创建对象都会被调用,提取构造共性
局部代码块:方法里的代码块,限制局部变量的范围

测试:

package cn.tedu.oopstatic;
/*本类用于学习静态代码块*/
/*执行顺序:
* 静态代码块->构造代码块->构造方法【对象创建成功】->局部代码块*/
public class TestStaticBlock {public static void main(String[] args) {//6.创建对象进行测试Person p = new Person();Person p2 = new Person();//7.触发局部代码块p.play();}
}//1.创建Person类
class Person{//8.创建静态代码块/*位置:类里方法外* 执行时机:静态代码块也属于静态资源,随着类的加载而加载,优先于对象加载*         并且静态资源只会加载一次* 作用:用于加载那些需要第一时间就加载,并且只加载一次的资源*/static{System.out.println("我是静态代码块");}//2.创建构造代码块/*位置:类里方法外执行时机:每次创建对象时被触发,并且优先于构造方法执行作用:用于提取所有构造方法的共性功能*/{System.out.println("我是构造代码块");}//5.创建构造方法public Person(){System.out.println("我是无参构造");}//3.创建普通方法public void play(){System.out.println("我是一个普通方法");//4.创建局部代码块/*位置:方法里* 执行时机:执行本局部代码块所在的方法时才会执行* 作用:用于限制变量的作用范围*/{System.out.println("我是一个局部代码块~");}}}

结论:执行顺序:静态代码块 --> 构造代码块 --> 构造方法 --> 局部代码块

2.6.6 常量

static final常量:应用率高

  • 必须声明同时初始化
  • 通过类名点来访问,并且不能被改变
  • 建议:常量所有字母都大写,多个单词用_分隔
  • 编译器在编译时会将常量直接替换为具体的数,效率高
  • 何时用:程序运行过程中数据永远不变,并且经常使用
public class StaticFinalDemo {public static void main(String[] args) {System.out.println(Aoo.PI); //常常通过类名点来访问//Aoo.PI = 3.1415926; //编译错误,常量不能被改变//1)加载Boo.class到方法区中//2)静态变量num一并存储到方法区中//3)到方法区中获取num的值并输出System.out.println(Boo.num);//编译器在编译时会将常量直接替换为具体的数,效率高//相当于System.out.println(5);System.out.println(Boo.COUNT);}
}class Boo{public static int num = 5; //静态变量public static final int COUNT = 50; //常量
}class Aoo{public static final double PI = 3.14159;//public static final int NUM; //编译错误,常量必须声明同时初始化
}

2.6.7 abstract 关键字—面向抽象编程

2.6.7.1 抽象类

  1. abstract 可以修饰方法或者类
  2. 被abstarct修饰的类叫做抽象类,被abstract修饰的方法叫做抽象方法
  3. 抽象类中可以没有抽象方法
  4. 如果类中有抽象方法,那么该类必须定义为一个抽象类
  5. 子类继承了抽象类以后,要么还是一个抽象类,要么就把父类的所有抽象方法都重写
  6. 多用于多态中
  7. 抽象类不可以被实例化
package day009;public class Test1_Animal {public void eat(){System.out.println("吃饭饭");}
}
/** 每种动物都需要吃,* 发现了,方法声明都一样,只是方法体不一样*
class Dog extends Test1_Animal{public void eat(){System.out.println("狗吃肉");}
}class Cat extends Test1_Animal{public void eat(){System.out.println("猫吃鱼");}
}*///上面的eat()声明都一样,就是方法体不一样,那就只抽取方法声明部分。
//The type Animal must be an abstract class to define abstract methodsabstract class Animal extends Object{//This method requires a body instead of a semicolonpublic abstract  void eat();
}//继承抽象类,并实现抽象方法
//The type Dog must implement the inherited abstract method Animal.eat()
abstract class Dog extends Animal{//可以实现抽象方法,也可以子类再变成一个抽象类
}class Cat extends Animal{public void eat() {System.out.println("猫吃鱼");}}

2.6.7.2 抽象方法

  • 由abstract修饰
  • 只有方法的定义,没有具体的实现(连{}都没有)
class A{public void eat(){//声明一样,可以提取syso("eat...B")    }
}
class B{public void eat(){//声明一样,可以提取syso("eat。。。A")   }
}
abstract class C{public abstract void eat();
}

补充:

  • 抽象方法的意义是什么?

    • 保证当发生向上造型时,通过超类的引用能点出那个方法来------------保证能点出来
  • 既然抽象方法的意义是保证能点出来,那为什么不设计为普通方法呢?
    • 设计为普通方法,意味着派生类可以重写也可以不重写,但设计为抽象方法,则可以强制派生类必须重写----------------强制派生类重写,以达到统一的目的

2.6.7.3 拓展

2.6.7.3.1 abstract注意事项

抽象方法要求子类继承后必须重写。
那么,abstract关键字不可以和哪些关键字一起使用呢?以下关键字,在抽象类中。用是可以用的,只是没有意义了。
1.private:被私有化后,子类无法重写,与abstract相违背。
2.static:静态优先于对象存在,存在加载顺序问题。
3.final:被final修饰后,无法重写,与abstract相违背。

2.6.8 关键字 this

  • 指代当前对象,哪个对象调用方法它指的就是哪个对象
  • this只能用在方法中,方法中访问成员变量之前默认有个this.
  • this的用法:
    • this.成员变量名----------------------访问成员变量
      注意:当成员变量与局部变量同名时,若想访问成员变量,则this不能省略
    • this.方法名()---------------------------调用方法(一般不用)
    • this()-------------------------------------调用构造方法(用得很少)
public class Student {String name;int age;String address;//构造方法Student(String name,int age,String address){this.name = name;       //ls.name="lisi"this.age = age;         //ls.age=24this.address = address; //ls.address="JMS"}void study(){System.out.println(this.name+"在学习...");}void sayHi(){System.out.println("大家好,我叫"+this.name+",今年"+this.age+"岁了,家住"+this.address);}
}public class ConsDemo {public static void main(String[] args) {//Student zs = new Student(); //编译错误,Student类没有无参构造方法Student zs = new Student("zhangsan",25,"LF");Student ls = new Student("lisi",26,"JMS");zs.sayHi();ls.sayHi();}
}

补充:
成员变量和局部变量是可以同名的,使用时默认采取的是就近原则,此时若想访问成员变量,则this不能省略。

3. 异常

前言:
异常贯穿于我们编程中的各个角落,是我们学习编程的过程中无法避免的话题,例如我们学习数组时,遇到过数组下标越界的异常。表达式除0时,会出现算术异常等等……接下来我们就来学习这个话题相关的知识
 
概述:
异常是一些用来封装错误信息的对象
它由异常的类型、提示信息、报错的行号提示三部分组成

3.1 异常的继承结构

3.2 异常的处理方式

当程序中遇到了异常,通常有两种处理方式:捕获或者向上抛出
当一个方法抛出异常,调用位置可以不做处理继续向上抛出,也可以捕获处理异常
大家可以结合生活中的例子:如果工作中遇到了问题,我们可以选择自己处理(捕获),或者交给上级处理(抛出)

捕获方式:

抛出方式:
对于不想现在处理或者处理不了的异常可以选择向上抛出
方式:在方法上设置异常的抛出管道,即:
在可能会会发生异常的方法上添加代码:
throws 异常类型
例如:void method1 throws Exception1,Exception2,Exception3{ }
TIPS:方法上有默认的异常管道:RuntimeException

3.3 异常测试

package cn.tedu.oop;import java.util.InputMismatchException;
import java.util.Scanner;/*本类用于异常的入门案例*/
public class ExceptionDemo {//public static void main(String[] args) throws Exception {//问题实际未处理,还报错public static void main(String[] args) {//method1();//调用暴露异常的方法//method2();//调用解决异常的方法--异常解决方案1--捕获处理--自己解决/*main()不直接调用会抛出异常的method3()* 而是调用f(),f()解决了method3()可能会抛出的异常*/f();//method3();//调用解决异常的方法--异常解决方案2--向上抛出--交给调用者来解决}//相当于在main()调用method3()之前解决了method3()可能会抛出的异常private static void f() {try {method3();}catch (Exception e){System.out.println("您输入的数据不对~请重新输入!");}}/*如果一个方法抛出了异常,那么谁来调用这个方法,谁就需要处理这个异常* 这里的处理也有两种方案:捕获解决 或者 继续向上抛出* 但注意:我们一般会在main()调用之前将异常解决掉* 而不是将问题抛给main(),因为没人解决了,该报错还报错*//*异常抛出的格式:在方法的小括号与大括号之间,写:throws 异常类型* 如果有多个异常,使用逗号分隔即可*///0.定义一个解决异常的方法-方案2//private static void method3() throws ArithmeticException,InputMismatchException{private static void method3() throws Exception{//1.复写一下刚刚的代码System.out.println("请您输入要计算的第一个整数:");int a = new Scanner(System.in).nextInt();System.out.println("请您输入要计算的第二个整数:");int b = new Scanner(System.in).nextInt();System.out.println(a/b);}/*异常捕获处理的格式:* try{*    可能会抛出异常的代码* }catch(异常的类型 异常的名字){*    万一捕获到了异常,进行处理的解决方案* }* try-catch结构可以嵌套,如果有多种异常类型需要特殊处理的话* *///0.定义一个解决异常的方法-方案1private static void method2() {//1.按照捕获处理的格式完成结构try{//2.复写一下刚刚的代码System.out.println("请您输入要计算的第一个整数:");int a = new Scanner(System.in).nextInt();System.out.println("请您输入要计算的第二个整数:");int b = new Scanner(System.in).nextInt();System.out.println(a/b);}catch(ArithmeticException e){//异常类型 异常名System.out.println("除数不能为0!");}catch (InputMismatchException e){System.out.println("请输入规定的整数类型!");/*使用多态的思想,不论是什么子异常,统一看作父类型Exception* 做出更加通用的解决方案,甚至可以只写这一个,上面2个不写了*/}catch (Exception e){System.out.println("您输入的数据不对~请重新输入!");}}//0.定义一个用来暴露异常的方法private static void method1() {//1.提示并接收用户输入的两个整数System.out.println("请您输入要计算的第一个整数:");int a = new Scanner(System.in).nextInt();System.out.println("请您输入要计算的第二个整数:");int b = new Scanner(System.in).nextInt();//2.输出两个数除法的结果//输入11和0,报错:ArithmeticException--算术异常,除数不能为0,数学规定//输入11和3.4,报错:InputMismatchException--输入不匹配异常System.out.println(a/b);/*1.不要害怕BUG,真正的勇士敢于直面自己写的BUG*//*2.学会看报错的信息提示,确定自己错误的方法*//*3.学会看报错的行号提示,确定自己报错的位置,哪里不对点哪里* 注意:源码不会错,要看的是自己写的代码*/}
}

3.4 扩展

3.4.1 catch 和 throws

异常处理只有两种方式: catch 和 throws,所以必须二选一
由于Java语法本身的特点,需要开发者事先考虑异常如何处理,也就是我们常说的:“未雨绸缪”
对于初级开发者来说,我们可能会捕获,但不处理异常
try {

} catch(Exception e) {
}
底层异常,应该向前抛到前面处理
经验少时,不知道该在什么位置捕获处理,应该选择 throws
但是大家需要注意,在异常抛出时,有些异常比如运行时异常,可能并不会强制要求抛出此异常,调用时也没有报错显示需要额外处理,这个时候就需要大家平时多积累,掌握良好的编码习惯了,手动添加代码进行预处理,增强程序的健壮性了。

3.4.2 程序错误类型

程序错误分为三种:

  • 编译错误(checked异常);
  • 运行时错误(unchecked异常);
  • 逻辑错误;
  1. 编译错误是因为程序没有遵循语法规则,编译程序能够自己发现并且提示我们错误的原因和位置,这个也是大家在刚接触编程语言最常遇到的问题。
  2. 运行时错误是因为程序在执行时,运行环境发现了不能执行的操作。
  3. 逻辑错误是因为程序没有按照预期的逻辑顺序执行。异常也就是指程序运行时发生错误,而异常处理就是对这些错误进行处理和控制。

其实我们还可以手动针对逻辑错误执行异常的抛出动作,大家可以理解成方法return,只不过此处我们返回的是异常,格式:(这里不是很理解)
if(逻辑错误有异常){ AException e = new AException(“提示消息”); throw e; }

package cn.tedu;import java.util.Scanner;public class TestThrow {public static void main(String[] args) {method4();}public static void method4(){//1.复写刚刚可能会发生异常的代码System.out.println("请输入您要计算的第一个数据:");int a = new Scanner(System.in).nextInt();System.out.println("请输入您要计算的第二个数据:");int b = new Scanner(System.in).nextInt();try{double result = divide(a,b);System.out.println(result);//System.out.println(a/b);}catch (ArithmeticException e){System.out.println("不能除0是我们的错,请鞭笞我们吧!");}}private static double divide(int a,int b) {if(b == 0){ArithmeticException e = new ArithmeticException("/ by zero");throw e;//类似于return e;}return a/b;}}

3.4.3 throws 与 throw的区别

  1. throws
    用在方法声明处,其后跟着的是异常类的名字
    表示此方法会抛出异常,需要由本方法的调用者来处理这些异常
    但是注意:这只是一种可能性,异常不一定会发生
  2. throw
    用在方法的内部,其后跟着的是异常对象的名字
    表示此处抛出异常,由方法体内的语句处理
    注意:执行throw一定抛出了某种异常

4. 接口 ---- 面向接口开发

4.1 概述

1.说明:
与之前学习过的抽象类一样,接口( Interface )在Java中也是一种抽象类型,接口中的内容是抽象形成的需要实现的功能,接口更像是一种规则和一套标准.
2.接口格式:

3.接口的特点:

  1. 通过interface关键字来定义接口
  2. 通过implements让子类来实现接口
  3. 接口中的方法全部都是抽象方法(JAVA8)
  4. 可以把接口理解成一个特殊的抽象类(但接口不是类!!!)
  5. 类描述的是一类事物的属性和方法,接口则是包含实现类要实现的方法
  6. 接口突破了java单继承的局限性
  7. 接口和类之间可以多实现,接口与接口之间可以多继承
  8. 接口是对外暴露的规则,是一套开发规范
  9. 接口提高了程序的功能拓展,降低了耦合性

4.2 入门案例


练习-1:创建接口

package cn.tedu.inter;
/*本接口用于创建接口测试*/
/*1.我们通过interface关键字来定义接口*/
public interface Inter {/*2.接口中可以定义普通方法吗?--不可以!*///public void eat(){}/*3.接口中可以定义抽象方法吗?--可以,接口中的方法都是抽象方法!*/public abstract void eat();public abstract void play();
}

练习-2:创建接口实现类

package cn.tedu.inter;
/*本类作为Inter接口的实现类*/
/*1.实现类如果想要实现接口定义的功能,需要与接口建立实现关系
* 通过关键字implements来建立实现类 实现 接口的关系*/
/*2.1 方案一:如果实现类与接口建立实现关系以后
可以选择不实现接口中的抽象方法,把自己变成一个抽象类*/
//abstract public class InterImpl implements Inter{//方案一
/*2.2方法二:如果实现类与接口建立实现关系以后
* 还可以选择实现接口中的所有抽象方法,把自己变成一个普通子类*/
public class InterImpl implements Inter{@Overridepublic void eat() {System.out.println("吃火锅");}@Overridepublic void play() {System.out.println("玩代码");}
}

练习-3:创建接口测试类

package cn.tedu.inter;
/*本类用于运行测试接口实现类*/
public class InterTests {public static void main(String[] args) {/*接口可以实例化吗?--不可以!!!*///Inter i = new Inter();//创建多态对象进行测试--不常用Inter i = new InterImpl();i.eat();i.play();//创建纯纯的接口实现类对象进行测试--推荐使用InterImpl i2 = new InterImpl();i2.eat();i2.play();}
}

4.3 接口的使用

4.3.1 练习: 接口之构造方法

package cn.tedu.inter2;
/**本类用于进一步测试接口的使用*/
public class TestUserInter {//5.创建入口函数main()public static void main(String[] args) {/**查看类的继承结构:Ctrl+O*/Inter2 i = new Inter2Impl();}
}
//1.创建接口
interface UserInter{//2.测试接口中是否包含构造方法//public UserInter(){}/*1.接口里没有构造方法*/
}//3.创建接口的实现类
class UserInterImpl implements UserInter{//4.创建实现类的构造方法public UserInterImpl(){/*2.如果一个类没有明确指定它的父类,那么它默认继承顶级父类Object*/super();/*3.此处调用的父类的无参构造是Object的无参构造*/System.out.println("我是子实现类的无参构造");}
}

总结:
1.接口里是没有构造方法的
2.如果一个类没有明确指定它的父类,那么它默认继承顶级父类Object,调用的super()是Object的无参构造
3.ctrl+o可以查看类的继承状态

4.3.2 练习: 接口之成员变量

package cn.tedu.inter2;
/*本类用于进一步测试接口的使用*/
public class TestUserInter {public static void main(String[] args) {//6.测试接口中的静态常量System.out.println(UserInter.age);//静态,因为可以被接口名直接调用//UserInter.age = 37;//final,因为值不可以被修改}
}
//1.创建接口
interface UserInter{//5.测试接口中是否可以定义成员变量/*4.接口中的是静态常量,实际上的写法是public static final int age = 20;* 只不过接口中可以省略不写,会默认拼接,所以写成 int age = 20;也可以*/public static final int age = 20;
}
//3.创建接口的实现类
class UserInterImpl implements UserInter{}

总结:
接口里没有成员变量,都是常量。所以,你定义一个变量没有写修饰符时,默认会加上:public static final

4.3.3 练习: 接口之成员方法

package cn.tedu.inter2;
/*本类用于进一步测试接口的使用*/
public class TestUserInter {public static void main(String[] args) {UserInterImpl u = new UserInterImpl();u.eat();u.play();}
}
//1.创建接口
interface UserInter{//7.测试接口中有抽象方法吗?/*5.接口中抽象方法的定义可以简写,会自动给方法拼接public abstract*/public abstract void eat();void play();
}
//3.创建接口的实现类
class UserInterImpl implements UserInter{@Overridepublic void eat() {System.out.println("实现接口中的抽象方法1");  }@Overridepublic void play() {System.out.println("实现接口中的抽象方法2");}
}

总结:
接口里的方法,默认都是抽象的,方法上会默认拼接public abstract。例如:public abstract void save();

4.4 接口的多继承多实现

package cn.tedu.inner2;import cn.tedu.inter.Inter;/*本类用于测试接口与类之间的复杂关系*/
public class TestRelation {public static void main(String[] args) {//创建对象进行功能测试Inter3Impl i = new Inter3Impl();i.save();i.delete();i.update();i.find();}
}//1.创建接口1
interface Inter1{void save();//保存功能void delete();//删除功能
}
//2.创建接口22
interface Inter22{void update();//更新功能void find();//查询功能
}
//3.创建接口1的实现类
class Inter1Impl implements Inter1{@Overridepublic void save() { }@Overridepublic void delete() { }
}//4.创建接口3,同时继承两个接口
/*1.接口可以继承接口,并且可以多继承,多个接口之间用逗号隔开*/
interface Inter3 extends Inter1,Inter22{ }//5.创建接口3的实现类
/*2.接口与实现类是实现的关系,并且可以多实现,多个接口之间用逗号隔开
* 对于Java中的类而言,遵循:单继承 多实现
* 一个类只能有一个父类,但是一个类可以实现多个接口*/
//class Inter3Impl implements Inter3{//写法1
class Inter3Impl implements Inter1,Inter22{//写法2@Overridepublic void save() {System.out.println("稍等...正在努力保存中...");}@Overridepublic void delete() {System.out.println("删除成功!");}@Overridepublic void update() {System.out.println("小二正在马不停蹄的更新~");}@Overridepublic void find() {System.out.println("客官,马上就查询好啦,稍等一丢丢~");}
}

4.5 总结

  1. 类与类的关系
    继承关系,只支持单继承
    比如,A是子类 B是父类,A具备B所有的功能(除了父类的私有资源和构造方法)
    子类如果要修改原有功能,需要重写(方法签名与父类一致 + 权限修饰符>=父类修饰符)

  2. 类和接口的关系
    实现关系.可以单实现,也可以多实现
    class A implements B,C{}
    其中A是实现类,B和C是接口,A拥有BC接口的所有功能,只是需要进行方法的重写,否则A就是抽象类

  3. 接口与接口的关系
    是继承关系,可以单继承,也可以多继承
    interface A extends B,C{}
    其中ABC都是接口,A是子接口,具有BC接口的所有功能(抽象方法) class X implements A{}
    X实现类需要重写ABC接口的所有方法,否则就是抽象类 class A extends B implements C,D{}
    其中A是实现类,也是B的子类,同时拥有CD接口的所有功能
    这时A需要重写CD接口里的所有抽象方法

  4. 接口与抽象类的区别

  • 接口是一种用interface定义的类型
    抽象类是一种用class定义的类型
  • 接口中的方法都是抽象方法,还有默认方法与静态方法
    抽象类中的方法不做限制
  • 接口中的都是静态常量
    抽象类中可以写普通的成员变量
  • 接口没有构造方法,不可实例化
    抽象类有构造方法,但是也不可以实例化
  • 接口是先天设计的结果,抽象是后天重构的结果
  • 接口可以多继承
    抽象类只能单继承

5. 内部类

5.1 概述

如果一个类存在的意义就是为指定的另一个类,可以把这个类放入另一个类的内部。
就是把类定义在类的内部的情况就可以形成内部类的形式。
A类中又定义了B类,B类就是内部类,B类可以当做A类的一个成员看待:

5.2 特点

  1. 内部类可以直接访问外部类中的成员,包括私有成员
  2. 外部类要访问内部类的成员,必须要建立内部类的对象
  3. 在成员位置的内部类是成员内部类
  4. 在局部位置的内部类是局部内部类

5.3 入门案例

package cn.tedu.innerclass;
/*本类用作测试内部类的入门案例*/
public class TestInner1 {public static void main(String[] args) {//3.创建内部类对象,使用内部类的资源/*外部类名.内部类名 对象名 = 外部类对象.内部类对象*/Outer.Inner oi = new Outer().new Inner();oi.delete();System.out.println(oi.sum);//4.调用外部类的方法--这样是创建了一个外部类的匿名对象,只使用一次new Outer().find();}
}//1.创建外部类 Outer
class Outer{//1.1创建外部类的成员变量String name;private int age;//1.2创建外部类的成员方法public void find(){System.out.println("Outer...find()");//6.测试外部类如何使用内部类的资源//System.out.println(sum);--不能直接使用内部类的属性//delete();--不能直接调用内部类的方法/*外部类如果想要使用内部类的资源,必须先创建内部类对象* 通过内部类对象来调用内部类的资源*/Inner in = new Inner();System.out.println(in.sum);in.delete();}//2.创建内部类Inner--类的特殊成员/*根据内部类位置的不同,分为:成员内部类(类里方法外)、局部内部类(方法里)*/class Inner{//2.1定义内部类的成员变量int sum = 10;//2.2定义内部类的成员方法public void delete(){System.out.println("Inner...delete()");//5.测试内部类是否可以使用外部类的资源/*结论:内部类可以直接使用外部类的资源,私有成员也可以!*/System.out.println(name);System.out.println(age);/*注意:此处测试完毕需要注释掉,否则来回调用* 会抛出异常StackOverFlowException栈溢出异常*///find();}}
}

5.4 成员内部类

5.4.1 被private修饰

package cn.tedu.innerclass;
/**本类用来测试成员内部类被private修饰*/
public class TestInner2 {public static void main(String[] args) {/**怎么使用内部类Inner2的资源?*///4.创建内部类Inner2对象进行访问//Outer2.Inner2 oi = new Outer2().new Inner2();//oi.eat();/**如果Inner2被private修饰,无法直接创建对象该怎么办?*///7.创建外部类对象,间接访问私有内部类资源new Outer2().getInner2Eat();}
}
//1.创建外部类Outer2
class Outer2{//6.提供外部类公共的方法,在方法内部创建Inner2内部类对象,调用内部类方法public void getInner2Eat() {Inner2 in = new Inner2();//外部类可以访问内部类的私有成员in.eat();}//2.1创建成员内部类Inner2/**成员内部类的位置:类里方法外*///5.成员内部类,被private修饰私有化,无法被外界访问private class Inner2{//3.创建内部类的普通成员方法public void eat() {System.out.println("我是Inner2的eat()");}}
}

总结:
成员内部类被Private修饰以后,无法被外界直接创建创建对象使用
所以可以创建外部类对象,通过外部类对象间接访问内部类的资源

5.4.2 被static修饰

package cn.tedu.innerclass;
/**本类用来测试成员内部类被static修饰*/
public class TestInner3 {public static void main(String[] args) {/**如何访问内部类的show()?*///4.创建内部类对象访问show()//方式一:按照之前的方式,创建内部类对象调用show()//Outer3.Inner3 oi = new Outer3().new Inner3();//oi.show();//方式二:创建匿名内部类对象访问show()//new Outer3().new Inner3().show();/**现象:当内部类被static修饰以后,new Outer3()报错*///6.用static修饰内部类以后,上面的创建语句报错,注释掉//通过外部类的类名创建内部类对象Outer3.Inner3 oi = new Outer3.Inner3();oi.show();//7.匿名的内部类对象调用show()new Outer3.Inner3().show();//9.访问静态内部类中的静态资源--链式加载Outer3.Inner3.show2();}
}//1.创建外部类Outer3
class Outer3{//2.创建成员内部类Inner3//5.内部类被static修饰—并不常用!浪费内存!static class Inner3{//3.定义成员内部类中普通的成员方法public void show() {System.out.println("我是Inner3类的show()");}//8.定义成员内部类的静态成员方法static public void show2() {System.out.println("我是Inner3的show2()");}}
}

总结:
静态资源访问时不需要创建对象,可以通过类名直接访问
访问静态类中的静态资源可以通过”. . . ”链式加载的方式访问

5.5 局部内部类

5.5.1 入门案例

package cn.tedu.innerclass;
/**本类用来测试局部内部类*/
public class TestInner4 {public static void main(String[] args) {/**如何使用内部类的资源呢?* 注意:直接调用外部类的show()是无法触发内部类功能的* 需要再外部类中创建内部类对象并且进行调用,才能触发内部类的功能* *///5.创建外部类对象调用show()//7.当在外部类show()中创建局部内部类对象并且进行功能调用后,内部类的功能才能被调用new Outer4().show();}
}
//1.创建外部类Outer4
class Outer4{//2.创建外部类的成员方法public void show() {//3.创建局部内部类Inner4—不太常用!!!/**位置:局部内部类的位置在方法里*/class Inner4{//4.创建局部内部类的普通属性与方法String name;int age;public void eat() {System.out.println("我是Inner4的eat()");}}/**如何使用局部内部类的资源?*///6.在show()里创建内部类对象Inner4 in = new Inner4();in.eat();System.out.println(in.name);System.out.println(in.age);}
}

5.5.2 匿名内部类

package cn.tedu.innerclass;
/*本类用于测试匿名内部类
* 匿名内部类没有名字,通常与匿名对象结合在一起使用*/
public class TestInner5 {public static void main(String[] args) {//传统方式:创建接口的实现类+实现类实现接口中的抽象方法+创建实现类对象+通过对象调用方法//3.创建接口一对应的匿名对象与匿名内部类,并调用实现了的方法save()new Inter1(){@Overridepublic void save() {System.out.println("save()...");}@Overridepublic void get() { }}.save();//5.创建抽象类对应的匿名对象与匿名内部类new Inter2(){@Overridepublic void drink() {System.out.println("一人饮酒醉");}}.drink();//7.调用普通类的功能怎么调用?创建匿名对象直接调用new Inter3().powerUp();new Inter3().powerUp();//new了2次,所以是两个匿名对象/*如果想要多次使用实现后的功能,还是要创建普通的对象* 匿名对象只能使用一次,一次只能调用一个功能* 匿名内部类其实就充当了实现类的角色,去实现未实现的抽象方法,只是没有名字而已*/Inter3 in = new Inter3();in.study();in.study();in.study();in.study();in.study();in.study();}
}//1.创建接口
interface Inter1{//2.定义接口中的抽象方法void save();void get();
}
//4.创建抽象类
abstract class Inter2{public void play(){System.out.println("Inter2...play()");}abstract public void drink();
}
//6.创建普通类
class Inter3{public void study(){System.out.println("什么都阻挡不了我想学习赚钱的决心");}public void powerUp(){System.out.println("我们会越来越强的!");}
}

总结:
匿名内部类属于局部内部类,而且是没有名字的局部内部类,通常和匿名对象一起使用

6. 拓展

6.1 静态变量和实例变量的区别

  1. 在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。
  2. 在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。

6.2 向下造型的补充

发生向下造型的前提是发生向上转型,否则会发生运行时异常

package cn.tedu;/*** @Author DELTA* @Date 2023-02-13-16:14* @Description:*/
public class OopTest {public static void main(String[] args) {//1.向下转型测试/*运行时异常:ClassCastException:cn.tedu.Animal cannot be cast to cn.tedu.Dog类型转换异常Dog d = (Dog) new Animal();*///2.发生向下转型前要向上造型Animal a = new Dog();Dog d = (Dog) a;System.out.println(d.age);System.out.println(d.name);}
}
class Animal{String name;
}
class Dog extends Animal{int age;
}

Java学习笔记-02(面向对象阶段)相关推荐

  1. JAVA学习笔记之面向对象(一)

    作为初入开发的萌新,我根据黑马程序员的教学视频和课件整理总结,记录下自己的JAVA学习,方便巩固和交流.每篇笔记首先回顾知识点,然后贴上代码和执行结果,最后进行小结.若有不正之处或者有疑问,欢迎指出, ...

  2. Java学习笔记:04面向对象-内部类_访问修饰符_final

    04面向对象-内部类/访问修饰符/final 1.static的介绍 static:关键字,静态的 static的作用是用来修饰类中的成员 2.访问一个类中的某一个成员变量 方法一: _1.创建对象 ...

  3. java学习笔记-第四阶段

    面向对象编程(高级部分) 文章目录 面向对象编程(高级部分) 一.类变量和类方法 二.理解main方法语法 三.代码块 四.单例设计模式 五.final关键字 六.抽象类 七.接口 八.内部类(重点) ...

  4. 【原】Java学习笔记018 - 面向对象

    1 package cn.temptation; 2 3 public class Sample01 { 4 public static void main(String[] args) { 5 // ...

  5. 【原】Java学习笔记020 - 面向对象

    1 package cn.temptation; 2 3 public class Sample01 { 4 public static void main(String[] args) { 5 // ...

  6. 【8-20】java学习笔记02

    others 初始化块在构造器前执行: 静态初始化块和实例变量显示初始化执行顺序为各自定义的位置: final类不能派生子类,final方法不可覆盖,final变量不可重新赋值: 判定值相等,Stri ...

  7. 疯狂java学习笔记之面向对象(二) - 成员变量与局部变量

    Java变量按其作用域可分为:成员变量和局部变量.注意:在Java中是没有全局变量这个概念的 一.成员变量: 成员变量是在类中定义的变量,具体可分为类变量与实例变量--有无static修饰 实例变量的 ...

  8. 疯狂java学习笔记之面向对象(三) - 方法所属性和值传递

    方法的所属性: 从语法的角度来看:方法必须定义在类中 方法要么属于类本身(static修饰),要么属于实例 -- 到底是属于类还是属于对象? 有无static修饰 调用方法时:必须有主调对象(主语,调 ...

  9. java学习笔记02

    此文章是写在二轮java复习,用来总结在刚开始学java时没注意的知识点. -------------------------------------------------------------- ...

最新文章

  1. iphone开发小技巧,转载
  2. Linux重启网络服务
  3. Java 集合框架部分面试题
  4. 将网页保存为webarchive文件的代码
  5. 【JZOJ4819】【NOIP2016提高A组模拟10.15】算循环
  6. 大学物理实验长度的测量实验报告_大学物理实验教案长度和质量的测量两篇
  7. java getcause_java - 如果在异常上调用getCause(),为什么还要处理Throwable - 堆栈内存溢出...
  8. 那些一毕业就选择华为的人,后来都怎么样了
  9. No package ‘libmarco-private‘ found
  10. git 回退上一个版本_世界上最流行的版本控制系统Git
  11. APMCM亚太地区数学建模历年赛题
  12. 在线发送免费传真(五个网上免费发传真网站介绍)
  13. (Pr)Premiere Pro 2022 软件下载+Pr安装教程
  14. java-opencv 米粒数_Python opencv学习音符的米粒数,返回每个米粒的位置面积和总米粒数的平均面积,pythonopencv,笔记,之数,并,一个,及,个数...
  15. Android Persistent常驻内存分析
  16. unity简单的脚本 播放3D立体音效(近大远小效果)
  17. 在线PS编辑器使用教程(Photoshop)
  18. mysql 手机号省份_根据手机号 判断省份和运营商
  19. 新型材料集成墙面,到底“新”在哪里?
  20. 用python三角形_python 三角形

热门文章

  1. VScode中配置 C/C++ 环境,超级详细,问题分析全面,绝对好用
  2. android 服务保活之白名单,Android保活从入门到放弃:乖乖引导用户加白名单吧(附7大机型加白示例)...
  3. 使用电销外呼系统的回拨线路真的不会封号吗?
  4. 【Vue】快乐学习第二篇
  5. android手机定时截屏软件,手机截图软件哪个好 安卓手机长截图
  6. FANUC机器人4种启动方式的具体操作步骤
  7. QGC地面站小白安装与简单实用
  8. 2017第49周六喝愚人水
  9. 初探Qt 3D Studio
  10. 非root查看手机数据库和SharedPreferences的方法