面向对象编程(高级)笔记

static

类变量:也就是静态变量,是所有该类的对象共享的,static变量在类加载的时候就生成了,可通过对象名访问,也可通过类名直接访问,要遵守修饰符规则。

1. 类变量也叫静态变量/静态属性,是该类的所有对象共享的变量。任何一个该类的对象去访问它,取到的都是相同的值,同样,任何一个对象去修改它,修改的也是同一个变量。

2. 定义语法(常用): 访问修饰符  static  数据类型 变量名;

3. 访问类变量: 类名.类变量名[推荐以这种形式访问]

                           对象名.类变量名

4. 类变量在类加载时就初始化了,也就是说,即使没有创建对象,只要类加载了,类变量就可以使用了。

5. 只要类还存在,类变量就存在,与对象无关。

类方法:也叫静态方法。

public static 数据返回类型 方法名(){}

类方法的调用与类变量相似。推荐使用类名直接访问。

类名.类方法名

1. 类方法不允许使用和对象有关的关键字(this、super)

2. 类方法中只能访问静态变量或静态方法。(普通成员方法既可以访问静态的也可以访问非静态的)

main

另外,在main()方法中,可以访问main方法所在类的静态属性静态方法,但是不能访问该类的非静态方法,必须实例化一个该类的对象去访问。 

代码块 

基本语法:

[修饰符] {

        代码;

};// (;)可省略

注意: 修饰符只能是static。带static的是静态代码块,不带的是普通代码块

使用细节:

1. static代码块作用是对类的初始化,随着类的加载而执行,并且只执行一次。普通代码块,每创建一个对象,就执行一次。(使用类的静态成员时,普通代码块不会被调用。)

2. 类在什么时候加载:【重点

        1)创建对象实例时(new)

        2)创建子类对象实例,父类也会被加载

        3)使用类的静态成员时(静态属性、静态方法)

3. 创建一个对象时,在一个类中调用顺序:

        1) (在创建对象时,先加载了类)调用静态代码块和静态属性初始化,它俩优先级相同,取决于定义顺序

        2) 调用普通代码块和普通属性初始化,它俩优先级相同,取决于定义顺序

        3) 调用构造方法

4. 构造器的最前面其实隐藏了super()和 调用普通代码块,静态相关的代码块和属性,在类加载时就执行完毕,因此,是优先于构造器和普通代码块执行的

class AA{
    public AA(){//构造器
        //这有隐藏的执行要求
        //(1) super()
        //(2) 调用代码块
        println("输出");
    }
}

 5. 创建一个子类时的调用顺序,看下图

final

final关键字用于表示常量。它可以与变量,方法和类一起使用。

任何实体(变量,方法或类)一旦被声明final后,只能分配一次。也就是,

  • final变量不能用另一个值重新初始化

  • final方法不能被重写

  • final类不能被继承

1. final修饰的属性又叫常量,用XX_XX_XX来命名。

2. final修饰的属性必须赋初值,且不能再修改,可再以下位置赋值:

        1) 定义时,如 private final double TAX_RATE = 0.21;

        2)在构造器中

        3) 代码块中,

3. 如果final修饰的是static属性时,只能在定义时or静态代码块中赋值。

4. final类不能被继承,可以实例化对象

5. final方法不能被重写,但可以被继承。

6. final不能修饰构造方法

7. final往往搭配static使用,效率更高,它不会导致类加载,底层编译器做了优化处理。

public class Test {
    public static void main(String[] args) {
        System.out.println(AA.num);
    }
}
class AA{
    public final static int num = 100;
    public static void method(){
        System.out.println("调用了静态方法");
    }
}

测试可知,只是输出了num,并没有输出方法里的语句,说明类并没有加载。

abstract

抽象类不能被实例化对象。         abstract只能修饰类和方法。

抽象类可以没有抽象方法。但有抽象方法的类必须是抽象类。

抽象类可以有任何成员,抽象类也是类。

抽象方法不能有主体(即不能加 { } )。

如果一个类继承了抽象类,那它比须实现抽象类的所有抽象方法,除非他自己也是抽象类。

抽象方法不能再用private\final\static修饰了,因为他们的作用是相反的。(前者需要继承,后者不需要继承)

接口

接口(interface): 接口就是将一些没有实现的方法封装到一起,到某个类要使用的时候,再根据具体情况将这些方法写出来

语法:

interface 接口名{
    //属性
    //方法
}

当别的类需要接入接口时,

class AA implements 接口名{
    自己属性;
    自己方法;
    必须实现接口中的抽象方法;
}

注意: jdk7.0前接口中的方法没有方法体。jdk8.0后接口中的方法可以有静态方法、默认方法。

interface Usb{
    void work(); //抽象方法
    default public void test(){
        //默认方法
    }
    public static void test2(){
        //静态方法
    }
}

细节:

1. 接口不能被实例化

2. 接口中所有方法都是public方法,接口中的抽象方法可以省略掉“abstract”

3. 普通接口要想接入接口,必须实现接口中的所有抽象方法。抽象类不需要。

4. 一个类可以实现多个接口: class AA implement 接口1, 接口2{ }

5. 接口中的属性都是final的,而且是 public static final  比如:

        int a = 1; 实际上是 public static final int a = 1;

        访问形式: 接口名.属性名

6. 接口不能继承其他类,但可以继承多个其他接口,多个。

        interface AA extends BB, CC; // AA BB CC 都是接口名

7. 接口的修饰符只能是public和默认,和类一样。

接口vs继承

继承的话,子类自动拥有父类的技能。如果子类想扩展技能的话,可以通过接口来实现。

可以理解 接口 是对 继承 的一种补充。

接口的作用:设计,设计好各种规范(方法),让其他类去实现

继承的作用:解决代码的复用性和可维护性。

接口比继承更灵活。

接口同继承一样,有多态特性:

可以向上转。向下转。有多态数组

另外,接口存在多态传递现象:

内部类

众所周知,类有五大成员,分别是,属性、方法、构造器、代码块,还有本节的主角--内部类。

内部类又根据定义位置不同分为:

                定义在外部类的局部位置上(方法、代码块中):

                                1. 局部内部类(有类名) 2. 匿名内部类(无类名)

                定义在外部类的成员位置上:

                                1. 成员内部类 2. 静态内部类

其中,匿名内部类较常用,也就是很重要!!!

局部内部类

/**
 * 局部内部类
 */
public class LocalInnerClass {
    public static void main(String[] args) {
        Outer01 outer01_xx = new Outer01();
        outer01_xx.method();

    }
}
class Outer01{
    private int n1 = 20;
    public void method(){
        //1. 局部内部类定义在类的局部位置,通常是方法或代码块中
        //2. 局部内部类不能用访问修饰符,除了final
        //3. 局部内部类本质上还是一个类(可以有类该有的东西)
        //5. 作用域:仅仅在定义他的方法或代码块
        class innerClass{//有类名
            //4. 局部内部类可以直接访问外部类的成员
            private int n1 = 80;
            public void innerMethod(){
                // 如果外部类和内部类的成员重名,遵循就近访问原则。
                // 如果想访问外部类成员,可以使用(外部类名.this.成员)去访问
                //因为Outer01.this本质上就是外部类的对象,相当于outer01_xx(在main中),
                // 可用hashcode值来验证
                System.out.println("n1 = " + n1 + "\n外部类的成员n1 = " + Outer01.this.n1);
                f1();
            }
        }
        //外部类可以通过创建内部类对象来访问内部类
        innerClass innerClass = new innerClass();
        innerClass.innerMethod();

    }


    private void f1(){
        System.out.println("外部方法");

    }
    private void f2(){
        //new innerClass()
        //外部其他类不能访问局部内部类,因为局部内部类是个局部变量;
    }
}

匿名内部类

/**
 * 匿名内部类
 */
public class AnonymousInnerClass {
    public static void main(String[] args) {
        Outer03 outer03 = new Outer03();
        outer03.method();

    }
}

class Outer03{//外部类
    public void method(){//方法
        //一、基于接口的匿名内部类
        //假设现在需要使用接口,传统方法是写一个类,实现该接口,并创建对象
        //Tiger tiger = new Tiger(); 或者:
        IA tiger = new Tiger();
        tiger.cry();
        //但是需求是Tiger/Dog只使用一次,后面不再使用
        //因此可以使用匿名内部类来简化开发
        // cat 编译类型 IA,
        // cat 运行类型 是匿名内部类 (底层分配类名 xxx ---> Outer03$1)
        /*
            底层:
            class xxx implements IA{
                public void cry() {
                    System.out.println("小猫喵喵叫~~~");
                }
            }

         */
        //jdk底层在创建匿名内部类时,就立即创建了Outer03$1实例,并把地址返回给了cat
        //匿名内部类使用一次,就不能在使用了。
        //  因为(个人理解)只在创建匿名内部类时创建了实例,之后就不能再创建了
        //但是这个对象cat是一直存在的,可以一直使用。
        IA cat = new IA() {
            public void cry() {
                System.out.println("小猫喵喵叫~~~");
            }
        };
        cat.cry();

        //二、基于类的匿名内部类
        //Father father = new Father("jack");  这样不加括号就是正常的创建了一个对象
        /*
            底层:
            class Outer03$2 extends Father{
                @Override
                public void test() {
                    System.out.println("重写了test方法");
                }
            }
            // 同时也返回了 匿名内部类Outer03$2的对象 给了father
         */
        Father father = new Father("jack"){//匿名内部类,加括号

            //可以重写test的方法
            @Override
            public void test() {
                System.out.println("重写了test方法");
            }
        };

        // 三、 基于抽象类的匿名内部类(必须实现抽象方法)
        new Animals(){
            void cry(){
                System.out.println("小猪 哼哼叫~~~");
            }
        };

    }

}
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{
    String name;

    public Father(String name) {
        this.name = name;
    }
    public void test(){

    }
}

abstract class Animals{
    abstract void cry();
}

注意匿名内部类底层的实现,以及它的运行类型是什么。

匿名内部类 可直接访问外部类成员,包括私有的。匿名内部类不能加访问修饰符。作用域仅在定义它的方法或代码块中。

外部类不能访问匿名内部类

匿名内部类有几种使用方法如下:

class Outer04{//外部类

    public void Method(){
        //匿名内部类的使用一
        Person p = new Person("Tom"){
            @Override
            public void introduce() {
                super.introduce();
            }
        };
        p.introduce();
        //匿名内部类的使用二
        new Person("Jerry"){
            public void hi(){
                System.out.println("hi my name is Jerry");
            }
        }.hi();
    }

}

class Person{
    private String name;

    public Person(String name) {
        this.name = name;
    }
    public void introduce(){
        System.out.println("我的名字是:" + name);
    }
}

成员内部类

静态内部类

  • 42
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值