当前位置:首页 » 《关于电脑》 » 正文

Java 复习 【知识改变命运】第九章

21 人参与  2024年12月07日 14:01  分类 : 《关于电脑》  评论

点击全文阅读


代码块,内部类

代码块1:代码块的基本介绍和基本语法2:体会代码块的用处3:代码块的细节4:创建一个对象时,在一个类中的调用顺序(难点) 单例设计模式1:介绍单例模式2:单例模式应用的实现1:饿汉式2:懒汉式 3:小结 内部类1:内部类的分类2:内部类的基本语法2.1:局部内部类2.1.1基本语法 2.2:匿名内部类2.2.1:基本语法2.2.2:最佳用法 3.1:成员内部类3.1.1:基本语法 4:静态内部类的使用4.1:基本语法

代码块

1:代码块的基本介绍和基本语法

代码块又被称为初始块,属于类中的成员,类似于方法把逻辑语句放在{}中,但是没有名字返回值,没有参数,也不能被调用,在加载类或者创建对象的时候被隐式调用。语法:
[修饰符] {代码};
修饰符可选且只能是static代码块分两种一种是静态代码块,一种是实例代码块/普通代码/非静态代码块;可以写上也可以省略

2:体会代码块的用处

相当于另外一种形式的构造体,可以进行初始化此操作当多个构造器中都有重复的语句,就可以抽取到初始代码块中,提高代码重用性
class CodeBlock01 {    public static void main(String[] args) {        Movie movie = new Movie("你好,李焕英");        System.out.println("===============");        Movie movie2 = new Movie("唐探 3", 100, "陈思诚");    }}class Movie {    private String name;    private double price;    private String director;//3 个构造器-》重载//老韩解读//(1) 下面的三个构造器都有相同的语句//(2) 这样代码看起来比较冗余//(3) 这时我们可以把相同的语句,放入到一个代码块中,即可//(4) 这样当我们不管调用哪个构造器,创建对象,都会先调用代码块的内容//(5) 代码块调用的顺序优先于构造器.. {System.out.println("电影屏幕打开...");System.out.println("广告开始...");System.out.println("电影正是开始...");};public Movie(String name) {        System.out.println("Movie(String name) 被调用...");        this.name = name;        }public Movie(String name, double price) {        this.name = name;        this.price = price;        }public Movie(String name, double price, String director) {        System.out.println("Movie(String name, double price, String director) 被调用...");        this.name = name;        this.price = price;        this.director = director;        }}

3:代码块的细节

static代码块也叫静态代码块,作用是对类进行初始化,而且它之随着类的加载而执行,且只会执行一次,如果是普通代块,每创建一个对象,执行一次类加载的几种情况:创建对象实例的时候,创建子对象的实例,父类类也会被加载,使用静态成员时(静态属性,静态方法)普通代码块:在创建对象实例的时候,会被隐形调用,被创建一次就会调用一次,如果使用类的静态成员,普通代码块并不会执行。static的=代码是类加载的时候,且只会被执行一次,普通代码块是创建对象的时候,创建一次对象执行一次
public class Code {    public static void main(String[] args) {//类被加载的情况举例//1. 创建对象实例时(new)// AA aa = new AA();//2. 创建子类对象实例,父类也会被加载, 而且,父类先被加载,子类后被加载//AA aa2 = new AA();//3. 使用类的静态成员时(静态属性,静态方法)// System.out.println(Cat.n1);//static 代码块,是在类加载时,执行的,而且只会执行一次.// DD dd = new DD(); //DD dd1 = new DD();//普通的代码块,在创建对象实例时,会被隐式的调用。// 被创建一次,就会调用一次。// 如果只是使用类的静态成员时,普通代码块并不会执行        System.out.println(DD.n1);//8888, 静态模块块一定会执行    }}class DD {    public static int n1 = 8888;//静态属性    //静态代码块    static {        System.out.println("DD 的静态代码 1 被执行...");//    }//普通代码块, 在 new 对象时,被调用,而且是每创建一个对象,就调用一次//可以这样简单的,理解 普通代码块是构造器的补充{    System.out.println("DD 的普通代码块...");}}class Animal {    //静态代码块    static {        System.out.println("Animal 的静态代码 1 被执行...");//    }}class Cat extends Animal {    public static int n1 = 999;//静态属性    //静态代码块    static {        System.out.println("Cat 的静态代码 1 被执行...");//    }}class BB {    //静态代码块    static {        System.out.println("BB 的静态代码 1 被执行...");//1    }}class AA extends BB {//静态代码块static {    System.out.println("AA 的静态代码 1 被执行...");//2}}

4:创建一个对象时,在一个类中的调用顺序(难点)

调用静态代码块和静态属性初始化:静态代码块和静态属性的调用优先级一样,如果有多个代码块和多个静态变量初始化,则按他们的顺序调用调用普通代码块和普通属性的初始化:两者调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按他们定义的顺序来调用
class A {    { //普通代码块        System.out.println("A 普通代码块 01");    }    private int n2 = getN2();//普通属性的初始化    static { //静态代码块        System.out.println("A 静态代码块 01");    }    //静态属性的初始化    private static int n1 = getN1();    public static int getN1() {        System.out.println("getN1 被调用...");        return 100;    }    public int getN2() { //普通方法/非静态方法        System.out.println("getN2 被调用...");        return 200;    }    //无参构造器    public A() {        System.out.println("A() 构造器被调用");    }}

在这里插入图片描述

构造器的最前面其实隐含了super()和调用普通代码块,静态代码块和静态属性初始化,在类的加载时候,就执行完成,因此优于构造器和普通代码块执行的
class A {public A() {//构造器//这里有隐藏的执行要求//(1)super();// (2)调用普通代码块System.out.println("ok");}}
public class Code{    public static void main(String[] args) {        new BBB();//(1)AAA 的普通代码块(2)AAA() 构造器被调用(3)BBB 的普通代码块(4)BBB() 构造器被调用    }}class AAA { //父类 Object    {        System.out.println("AAA 的普通代码块");    }    public AAA() {//(1)super()//(2)调用本类的普通代码块        System.out.println("AAA() 构造器被调用....");    }}class BBB extends AAA {    {        System.out.println("BBB 的普通代码块...");    }    public BBB() {//(1)super()//(2)调用本类的普通代码块        System.out.println("BBB() 构造器被调用....");    }}
总结:创建一个子类父类对象时候(继承关系),他们的静态代码,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:1:父类的静态方法和的静态属性(优先级一样,按定义的顺序)2:子类的静态代码块和静态属性(优先级一样,按定义的顺序)3:父类的普通代码块和普通属性初始化(优先级一样,按定义的顺序执行)4:父类的构造方法5:子类的普通代码块和普通属性初始化(优先级一样,按定义的顺序执行)6:子类的构造方法
class Sample{    Sample(String s)    {        System.out.println(s);    }    Sample()    {        System.out.println("Sample 默认构造函数被调用");    }}//====public class Test{    Sample sam1=new Sample("sam1 成员初始化");//    static Sample sam=new Sample("静态成员 sam 初始化 ");//    static{        System.out.println("static 块执行");//        if(sam==null)System.out.println("sam is null");    }    Test()//构造器    {        System.out.println("Test 默认构造函数被调用");//    }    //主方法    public static void main(String str[])    {        Test a=new Test();//无参构造器    }}//运行结果, 输出什么内容,并写出. 2min 看看//1. 静态成员 sam 初始化//        2. static 块执行//        3. sam1 成员初始化//        4. Test 默认构造函数被调用

单例设计模式

1:介绍单例模式

所谓的单机设计模式,就是采用一定的方法保证在整个软件系统中,对某个类只存在一个对象实例,并且该类只提供一个取得对象实例的方法单例模式有两种方法:饿汉式和懒汉式

2:单例模式应用的实现

public class Test {    public static void main(String[] args) {        GirlFriend xh = new GirlFriend("小红");        GirlFriend xb = new GirlFriend("小白");    }}class GirlFriend {    private String name;    public GirlFriend(String name) {        this.name = name;    }}问题抛出,我们只要有一个女朋友对象,怎么去实现呢?
创建方法:构造器私有化(防止直接new),类的内部创建对象,向外暴露一个静态公共方法。

1:饿汉式

public class Test {    public static void main(String[] args) {        GirlFriend instance1 = GirlFriend.getInstance();        System.out.println(instance1);        GirlFriend instance2 = GirlFriend.getInstance();        System.out.println(instance2);        System.out.println(instance1 == instance2);        System.out.println(GirlFriend.n1);    }}class GirlFriend {    public static int n1 = 100;    private String name;    //第一步将构造器私有化    private GirlFriend(String name) {    System.out.println("构造方法被调用。。。");        this.name = name;            }    //第二部在类的内部创建一个静态的对象    private static GirlFriend gf = new GirlFriend("小红");    //第三步提提供一个方法,返回一个对象的引用    public static GirlFriend getInstance() {        return gf;    }    @Override    public String toString() {        return "GirlFriend{" +                "name='" + name + " " +"age:"+n1+""+                '}';    }}

饿汉式的缺点:饿汉式,一般创造重量级的对象,但是有可能创建了对象没有使用,造成资源的浪费

2:懒汉式

class Cat{    public static int n1 = 999;    private String name;    private static Cat cat;    //构造器私有化    private Cat(String name) {        this.name = name;        System.out.println("构造方法被调用");    }    //提供一个静态的方法,返回一个对象的引用    public static Cat getInstance() {        if(cat==null) {            //创建一个对象            cat = new Cat("小白");        }        return cat;    }    @Override    public String toString() {        return "Cat{" +                "name='" + name + '\'' +                '}';    }}public class Test {    public static void main(String[] args) {//        Cat cat1 = Cat.getInstance();//        System.out.println(cat1);//        Cat cat2 = Cat.getInstance();//        System.out.println(cat2);//        System.out.println(cat1 == cat2);        System.out.println(Cat.n1);    }}

懒汉式缺陷:会存在线程安全问题,当多个线程同时调用getInstance()时候,会产生线程安全问题。

3:小结

二者的区别在于创建对象的时机不同,饿汉式在类加载时候创建实例对象,懒汉式是在使用时候才创建饿汉式不存在线程问题,懒汉式存在线程安全问题饿汉式存在浪费资源的可能(程序员创建后不使用),懒汉式不存在浪费资源的问题在我们javaSE标准类中,java.lang.Runtime就是经典的单例模式
在这里插入图片描述

内部类

前言:内部类是在一个类的内部又听到的另一个类的结构,被嵌套的类成为内部类,嵌套其他类的对象成为外部类

1:内部类的分类

按位置可以分为两类:在属性位置上和在方法里面的内部类定义在类的局部位置(方法/代码块)(1)局部内部类(有类名),(2)匿名内部类(没有类名)定义在成员位置,(1)成员内部类(没有static修饰),(2)静态内部类(有static修饰)

2:内部类的基本语法

2.1:局部内部类

2.1.1基本语法
说明:局部内部类是定义在外部类的局部位置,比如方法中(方法块中),并且有类名1:可以直接防蚊外部类的成员和方法,包括私有的2:不能添加访问修饰符,因为它的地位就是一个局部变量,局部变量是不能使用修饰符的,但是可以使用final和abstract修饰,因为局部变量也可以使用final3:作用域仅仅是它的方法体内或者是代码块内4:局部内部类----访问------->外部类成员【直接访问】5:外部类----访问----->局部内部类的成员,访问方式:创建对象,在访问(必须在作用域内)6:外部其他类-----不能访问----->局部内部类(因为局部内部类的地位是一个局部变量)6:如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果访问外部类的成员,则可以使用(外部类名.this.成员)记住:(局部内部类定义在方法中/代码块),作用域在方法体或者代码块,本质还是一个类
class Outer{ //外部类方法{class Inner//}}
public class LocalInnerClass {//    public static void main(String[] args) {//演示一遍        Outer02 outer02 = new Outer02();        outer02.m1();        System.out.println("outer02 的 hashcode=" + outer02);    }}class Outer02 {//外部类    private int n1 = 100;    private void m2() {        System.out.println("Outer02 m2()");    }//私有方法    public void m1() {//方法//1.局部内部类是定义在外部类的局部位置,通常在方法//3.不能添加访问修饰符,但是可以使用 final 修饰//4.作用域 : 仅仅在定义它的方法或代码块中        final class Inner02 {//局部内部类(本质仍然是一个类)//2.可以直接访问外部类的所有成员,包含私有的private int n1 = 800;            public void f1() {//5. 局部内部类可以直接访问外部类的成员,比如下面 外部类 n1 和 m2()//7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,// 使用 外部类名.this.成员)去访问// 老韩解读 Outer02.this 本质就是外部类的对象, 即哪个对象调用了 m1, Outer02.this 就是哪个对象                System.out.println("n1=" + n1 + " 外部类的 n1=" + Outer02.this.n1);                System.out.println("Outer02.this hashcode=" + Outer02.this);                m2();            }        }//6. 外部类在方法中,可以创建 Inner02 对象,然后调用方法即可        Inner02 inner02 = new Inner02();        inner02.f1();    }}

2.2:匿名内部类

2.2.1:基本语法
1:本质还是类,内部类,该类没有名字,同时还是一个对象2:匿名内部类定义在外部类的局部位置,比如方法和方法体3:内部类的基本语法
new (抽象)类或者接口(参数列表) {类体};
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$1class Outer04$1 implements IA {@Overridepublic 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{@Overridepublic void test() {System.out.println("匿名内部类重写了 test 方法");}}*///4. 同时也直接返回了 匿名内部类 Outer04$2 的对象//5. 注意("jack") 参数列表会传递给 构造器        Father father = new Father("jack"){            @Override            public void test() {                System.out.println("匿名内部类重写了 test 方法");            }        };        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 Tiger implements IA {//// @Override// public void cry() {// System.out.println("老虎叫唤...");// }//}//class Dog implements IA{// @Override// public void cry() {// System.out.println("小狗汪汪...");// }//}class Father {//类    public Father(String name) {//构造器        System.out.println("接收到 name=" + name);    }    public void test() {//方法    }}abstract class Animal { //抽象类    abstract void eat();}
2:匿名类的语法比较特殊,匿名类即使一个类的定义,也是一个对象,从语法层面上看,它既有定义类的特征,也有创建对象的特征,因此可以调用匿名内部类的方法3:可以直接访问外部所有类的成员,包括私有的4:不能添加访问修饰符,因为它的地位是一个局部变量5:作用域:仅仅是它这个方法内,或者代码块内6:匿名内部类-----访问-----外部类成员(直接访问)7:外部其他类不能访问匿名内部类(因为匿名内部类是一个局部变量)8:如果外部类和匿名内部类的成员重名时,匿名内部类访问,,默认执行就近原则,想要访问外部类成员,则可以使用(外部类名.this.成员)去访问
public class AnonymousInnerClass {        public static void main(String[] args) {        Outer05 outer05 = new Outer05();        outer05.f1();    //外部其他类---不能访问----->匿名内部类        System.out.println("main outer05 hashcode=" + outer05);    }}class Outer05 {    private int n1 = 99;    public void f1() {//创建一个基于类的匿名内部类//不能添加访问修饰符,因为它的地位就是一个局部变量//作用域 : 仅仅在定义它的方法或代码块中        Person p = new Person(){            private int n1 = 88;            @Override            public void hi() {//可以直接访问外部类的所有成员,包含私有的//如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,//默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.this.成员)去访问                System.out.println("匿名内部类重写了 hi 方法 n1=" + n1 +                        " 外部内的 n1=" + Outer05.this.n1 );//Outer05.this 就是调用 f1 的 对象                System.out.println("Outer05.this hashcode=" + Outer05.this);            }        };        p.hi();//动态绑定, 运行类型是 Outer05$1//也可以直接调用, 匿名内部类本身也是返回对象// class 匿名内部类 extends Person {}// new Person(){// @Override// public void hi() {// System.out.println("匿名内部类重写了 hi 方法,哈哈...");// }// @Override// public void ok(String str) {// super.ok(str);// }// }.ok("jack");    }}class Person {//类    public void hi() {        System.out.println("Person hi()");    }    public void ok(String str) {        System.out.println("Person ok() " + str);    }}//抽象类/接口...
2.2.2:最佳用法
public class InnerClassExercise01 {    public static void main(String[] args) {//当做实参直接传递,简洁高效        f1(new IL() {            @Override            public void show() {                System.out.println("这是一副名画~~...");            }        });//传统方法        f1(new Picture());    }    //静态方法,形参是接口类型    public static void f1(IL il) {        il.show();    }}//接口interface IL {    void show();}//类->实现 IL => 编程领域 (硬编码)class Picture implements IL {    @Override    public void show() {        System.out.println("这是一副名画 XX...");    }}

3.1:成员内部类

3.1.1:基本语法
说明:成员内部类是定义在外部类的成员位置,并且没有static修饰1:可以直接访问外部类的所有成员,包括私有的2:可以添加任意的访问修饰符,因为它的地位就是一个成员3:作用域:和外部类的其他成员一样,为整个类体4:成员内部类-----访问----->外部类成员(直接访问)、5:外部类------访问----->成员内部类(先创造对象,访问)6:外部其他类-----访问-----成员内部类(创造外部类对象)7:如果外部类和内部类成员重名时,内部类访问的话,默认遵循就近原则,如果像访问外部类的成员,则可以使用(外部类.this.成员)去访问
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);    }}

4:静态内部类的使用

4.1:基本语法
说明静态内部类是定义在外部类的成员位置,并且有static修饰1:可以最直接访问外部类所有静态成员,包含私有的,但不能直接访问非静态成员2:可以添加任意访问修饰符,因为它的地位是一个成员3:作用域:同其他成员,是整个类体4:静态内部类----访问---->外部类(比如静态属性)(直接访问所有的静态属性成员)5:外部类—访问------静态内部类 访问方式:创建对象,再访问6:其他外部其他类—访问—静态内部类7:如果外部类和静态内部类的成员重名时,静态内部类访问时,默认遵循就近原则,如果访问外部类成员,则可以使用(类名,成员)
public class StaticInnerClass01 {    public static void main(String[] args) {        Outer10 outer10 = new Outer10();        outer10.m1();//外部其他类 使用静态内部类//方式 1//因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)        Outer10.Inner10 inner10 = new Outer10.Inner10();        inner10.say();//方式 2//编写一个方法,可以返回静态内部类的对象实例. Outer10.Inner10 inner101 = outer10.getInner10();        System.out.println("============");        inner101.say();        Outer10.Inner10 inner10_ = Outer10.getInner10_();        System.out.println("************");        inner10_.say();    }}class Outer10 { //外部类    private int n1 = 10;    private static String name = "张三";    private static void cry() {}//Inner10 就是静态内部类//1. 放在外部类的成员位置//2. 使用 static 修饰//3. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员//4. 可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员//5. 作用域 :同其他的成员,为整个类体static class Inner10 {    private static String name = "代阳";    public void say() {//如果外部类和静态内部类的成员重名时,静态内部类访问的时,//默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.成员)        System.out.println(name + " 外部类 name= " + Outer10.name);        cry();    }}    public void m1() { //外部类---访问------>静态内部类 访问方式:创建对象,再访问        Inner10 inner10 = new Inner10();        inner10.say();    }    public Inner10 getInner10() {        return new Inner10();    }    public static Inner10 getInner10_() {        return new Inner10();    }}

点击全文阅读


本文链接:http://zhangshiyu.com/post/197580.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1