大家好我是你们可爱的华华,几个小时不见想我了吗???
今天我们继续讲面向对象思想
上回我们说到类的三大分类:具体类 抽象类 接口,这三者的关系和互相继承实现一定程度上会让代码变得非常灵活,但类其实还有一种类叫做:
内部类
这种类最大的特点,他不会以java文件的形式存在于我们的项目中
是将一个类定义在另一个类的内部(禁止套娃)
有的时候我们经常会发现,在一个类中需要做些事的时候,可能需要调用另一类的工具,(比如一个方法用一个对象作为参数)但它其实只被使用了一次(工具人实锤)
这时候还要为此创建一个类文件其实很麻烦
内部类的出现就一定程度上解决了这个问题,但它也一定程度上破坏了代码的可读性
内部类有四种:
成员内部类、局部内部类、匿名内部类、静态内部类
一、成员内部类:
将一个类直接定义在类的里面,和类的属性是同级
和一般类一样可以 使用所有类别修饰符来修饰
a优点:
1、省略一个.java文件
2、成员内部类种可以访问外部所有成员包括私有元素
b创建对象:
内部类属于一个类不会独立存在,要调用内部类的构造器只能创建外部类的对象通过对象来调用内部类的构造器
public class Person {
public class InnerPerson{
public void InnerPersonSay(){
System.out.println("我是内部类");
}
}
}
public class TextMain {
public static void main(String []args){
Person.InnerPerson innerPerson=new Person().new InnerPerson();
innerPerson.InnerPersonSay();
}
}
c内外部类调用:
1.成员内部类可以访问外部所有成员包括"私有元素"(咱两谁跟谁我都是你的呢宝贝)
2.有时候可能能有方法名和属性名内外部类相同情况,这时候如果想要内部类对象调用外部类成员 外部类.this.xxxx
public class Person {
private String name ="123";
public class InnerPerson{
private String name="456";
public void InnerPersonSay(){
System.out.println(Person.this.name);//123
System.out.println(this.name);//456
}
}
}
注:
内部类存在后 对java源代码进行编译 生成一个字节码
“外部类名”$“内部类名”.class
二、局部内部类
1将一个类定义在方法/块里面
2像一个局部的变量一样,不能用public protected private和static 修饰//我只是个方法用完了就抛弃的对象而已不值得被静态
3只有abstract 或者final能够修饰
4局部内部类产生的class文件 “外部类名”1“内部类名”
5局部内部类肯定不止一个,因为是定义在不同方法里,同名是允许出现这时候就用数字作为辨别
6局部内部类中使用的局部变量都强制需要加final修饰
原因:局部内部类的东西,编译字节码已经定义好了,放在类模板里面,变量的内容可以改变,这我是不会允许的
三、匿名内部类
这种类真的是内部类中比较常见的那种了
他的作用就是为了达到临时的实现的一个接口这个目前,而又不创建一个具体类(呸渣男石锤)
这种形式经常被用作策略模式(总结这种模式就是一个抽象类名或者接口名,可以变化成不同类的功能,这也是java编程思想带来的灵活)
Text t =new Text(){
//在这里我要去实现这个借口啦
@Override
public void say() {
System.out.println("我是重写Text借口后的say方法");
}
};
特性:
1.匿名内部类很特殊,只有类体,没有类的所有结构(修饰符 名字 继承 实现这些我们都没有,咋用完就放弃的小人人)
2.它是随着外部类的创建而创建的,没有构造方法,我都没有名字咋调用构造方法
3.它不能用任何修饰符来修饰(任何东西的装饰都比不上你(名字)的离开)
类加载过程:
类加载过程真的!!!真的!!真的!!
笔试如果考面向对象思想,类加载真的必考必考
类加载过程分为三大步:
加载、连接、初始化
一、加载
将类的class⽂件通过io读⼊内存,创建⼀个java.long.class对象也就是说,当程序使⽤任何类时,系统都会为它建⽴⼀个对应的class对象(⽤来描述这个类)需要的类加载器由jvm提供(叫系统类加载器)
开发者可以通过继承classloader类来创建⾃⼰的类加载器。对这个class⽂件通过反射形成类映射
(其实类加载器在反射时候我们经常接触它,你得到一个一个类class时候也是调用类类加载器,之后的JDBC 我们调出DriverManager 对象我们有四种方法调出来加载器来创建这个对象(挖坑+1))
Thread.currenthread().getContextClassLoader()得到⼀个类加载器.getresourceass(回去当前路径src来读取⽂件)
类加载器加载的数据来源如下:
1本地class⽂件;
2从jar包加载class⽂件,
3把⼀个java源⽂件动态编译
二、连接:
1验证:是否有正确的内部接口
2准备:类准备阶段则负责为类变量分配内存,并设置默认初始值
(只有类的变量才有这份殊荣哦)
3解析:将类的二进制数据中的符号引用换成直接引用
三、初始化:
什么时候初始化:
1.通过new 创建对象 通过反射创建对象 ,通过反序列化创建对象
(对,java创建对象不仅仅只是new ,反射和反序列化都是!!这两个玩意真的很好玩)
2.调用某个类的方法(类的方法肯定是静态的)
3.访问某个类或者接口的变量,或为该变量赋值
4.使用反射方式来强制,创建某个类或接口对应的class对象
5.初始化某个类的子类,当初始化某个类的子类时候该子类所有的父类都会被初始化(先有爸爸才能有儿子)
初始化过程:
1初始化父类:1静态属性、2静态方法、3静态块、4执行父类静态块
2初始化子类:1静态属性、2静态方法、3静态块、4执行子类静态块
3开辟空间:
加载:
父类非静态属性、
父类非静态方法、
父类非静态块、
父类构造方法、
子类非静态属性、
子类非静态方法、
子类非静态块、
子类构造方法、
4执行:
父类非静态块、
父类构造方法、
子类非静态块
子类构造方法
(执行了静态块之后,剩下的都得先加载了才能执行)
实例:
public abstract class Person {
public static String personName="我是父类的静态属性";
public String name="我是父类的非静态属性";
static{
System.out.println(personName+"你看我加载完了吧");
System.out.println("我是父类的静态块我优先执行,尊老,爱幼就算了");
}
public void sayPerson(){
System.out.println("我是父类的非静态方法");
}
{
System.out.println(name);
sayPerson();
System.out.println("我是父类的方法块我开始执行拉");
}
public Person(){
System.out.println("我是父类的构造方法我被执行拉");
}
}
public class Man extends Person {
public static String ManName="我是子类的静态属性";
public String name="我是子类的非静态属性";
public void say(){
System.out.println("我是子类的非静态方法");
}
static {
System.out.println(ManName+"看看我被加载了吧");
System.out.println("我是子类的静态方法我执行了");
}
{
System.out.println(name);
say();
System.out.println("我是子类的非静态块,我被执行拉");
}
public Man(){
System.out.println("我是子类的构造方法,我最后一个呗执行");
}
}
先讲这两章,也足够各位去消化了
我是霜华,一位渴望去西溪园区看小姐姐的后浪
我们明天见!!!