美文网首页
Java入门教程-面向对象查漏补缺

Java入门教程-面向对象查漏补缺

作者: 王一萍o叩丁狼教育 | 来源:发表于2018-09-13 17:07 被阅读0次

    1. 面向对象查漏补缺

    1.1. this关键字(重点掌握)

    什么是this:表示当前对象

    this主要存在于两个位置:

    • 在构造器中:表示当前被创建的对象

    • 在方法中:哪一个对象调用this所在的方法,此时this就表示哪一个对象

    public class Cat {
    
        private String name;
    
        private int age;
    
        public Cat() {
    
            System.out.println("构造器中:"+ this);  //当前创建的对象
    
        }
    
        public void say() {
    
            System.out.println("say方法中:"+ this);  //当前调用say方法的对象
    
            System.out.println("名字=" + this.name + ",年龄=" + this.age);
    
        }
    
        public void setName(String name) {
    
            this.name = name;
    
        }
    
        public void setAge(int age) {
    
            this.age = age;
    
        }
    
    }
    

    测试代码:

    public class ThisDemo {
    
        public static void main(String[] args) {
    
            Cat c1 = new Cat();  //此时构造中的this就是当前创建的c1对象
    
            c1.setName("加菲");
    
            c1.setAge(5);
    
            c1.say();  //此时say方法中的this就是c1对象
    
            Cat c2 = new Cat();//此时构造中的this就是当前创建的c2对象
    
            c2.setName("Tom");
    
            c2.setAge(3);
    
            c2.say();  //此时say方法中的this就是c2对象
    
        }
    
    }
    

    运行测试:

    构造器中  :cn.wolfcode._01_this.Cat@15db9742
    
    say方法中  :cn.wolfcode._01_this.Cat@15db9742
    
    名字=加菲,年龄=5
    
    构造器中  :cn.wolfcode._01_this.Cat@6d06d69c
    
    say方法中  :cn.wolfcode._01_this.Cat@6d06d69c
    
    名字=Tom,年龄=3
    

    什么时候需要使用this:

    • 解决局部变量和成员变量之间的二义性,此时必须使用

    • 同一个类中非static方法间互调(此时可以省略this,但是不建议省略)

    • 构造器重载的互调(看懂即可)

    public class Dog {
    
        private String name;
    
        private int age;
    
        public Dog() {
    
        }
    
        public Dog(String name) {
    
            this(name, 0);// 调用两个参数的构造器,必须放在构造器第一行
    
            // TODO其他操作
    
        }
    
        public Dog(String name, int age) {
    
            this.name = name;
    
            this.age = age;
    
        }
    
        public void say() {
    
            String name = "局部变量";
    
            System.out.println(name);   // 访问局部变量
    
            System.out.println(this.name);  // 访问成员变量
    
            this.other();// 调用当前类中非static方法
    
        }
    
        public void other() {
    
            System.out.println(this.age);//此时的this是谁
    
        }
    
    }
    

    1.2. super关键字(重点掌握)

    什么是super:

    this :表示当前对象,谁调用this所在的方法,this就是哪一个对象

    super :当前对象的父类对象

    在创建子类对象时,在子类构造器的第一行会先调用父类的构造器。

    什么时候使用super:

    • 在子类方法中,调用父类被覆盖的方法,此时必须使用super

    • 在子类构造器中,调用父类构造器,此时必须使用super语句

    父类代码:

    public class Person {
    
        private String name;
    
        private int age;
    
        public Person() {
    
        }
    
        public Person(String name, int age) {
    
            this.name = name;
    
            this.age = age;
    
        }
    
        public void doWork() {
    
            System.out.println("Person...doWork...");
    
        }
    
    }
    

    子类代码:

    public class Student extends Person {
    
        private String sn;
    
        public Student(String sn) {
    
            super();// 隐式调用父类无参数构造器,必须作为构造第一行
    
            this.sn = sn;
    
        }
    
        public Student(String name, int age, String sn) {
    
            super(name, age);// 显示去调用父类无参数构造器,必须作为构造第一行
    
            this.sn = sn;
    
        }
    
        public void doWork() {
    
            super.doWork();  //  ?此时调用谁的方法
    
            this.doWork();  //  ?此时调用谁的方法
    
            System.out.println("Student...doWork...");
    
        }
    
    }
    

    1.3. static修饰符(掌握)

    static修饰的字段和方法直接属于类,不属于该类的对象。记住:字段和方法属于谁,就让谁来调用。

    • 使用static修饰的成员: 属于类 直接使用类名调用即可

    • 没有使用static修饰的成员: 属于对象 必须先创建对象,再调用

    注意:static方法不能使用super和this:

    因为static是类级别的,super和this是对象级别的,存在类的时候不一定存在对象,也就说使用类名调用static方法时,此时可能是没有对象的。

    测试代码:

    public class Dog {
    
        public static int totalNumber = 100;
    
        public int age;
    
        public void m1() {
    
            System.out.println("实例方法");
    
        }
    
        public static void m2() {
    
            System.out.println("静态方法");
    
        }
    
    }
    

    public class StaticDemo {
    
        public static void main(String[] args) {
    
            Dog d1 = new Dog();
    
            d1.age = 5;
    
            Dog d2 = new Dog();
    
            d2.age = 15;
    
             //调用代码再后面
    
        }
    
    }
    

    内存分析:

    static修饰的成员变量(字段),随着所在类被加载进JVM,也同时存储在方法区中,被所有对象共享。

    image.png

    实例成员和类成员的访问规则:

    d1.m1();//  实例方法
    
    d2.m1();//  实例方法
    
    // Dog.m1(); 语法报错
    
    d1.m2();//静态方法   底层使用类名访问
    
    d2.m2();//静态方法   底层使用类名访问
    
    d1.m2();//静态方法   底层使用类名访问
    
    Dog.m2();
    
    System.out.println(d1.age);// 5
    
    System.out.println(d2.age);// 15
    
    // System.out.println(Dog.age); 语法报错
    
    System.out.println(d1.totalNumber);//100   底层使用类名访问
    
    System.out.println(d2.totalNumber);//100   底层使用类名访问
    
    System.out.println(Dog.totalNumber);//100
    

    使用对象访问static方法或成员变量,底层依然使用类名访问的。

    一般的,static方法访问的成员变量必须使用static修饰。

    最后记住结论:

    • 类 成 员:使用static修饰的字段和方法 : 属于类 直接使用类名调用即可

    • 实例成员:没有使用static修饰的字段和方法: 属于对象 必须先创建对象,再调用

    1.4. final修饰符(掌握)

    继承关系最大弊端是破坏封装,子类可以继承父类的实现细节,也可以通过方法覆盖的形式修改功能实现细节。那么怎么来限制某个类不能有子类,不能覆盖方法?——final修饰符。

    final的含义是最终的,不可改变的,可以修饰类、方法、变量。

    • final修饰的类:表示最终的类, 该类不能再有子类
    final public class Super {
    
    }
    
    public class Sub  extends Super{  //此行语法报错
    
    }
    
    • final修饰的方法:最终的方法,该方法不能被子类覆盖
    public class Super {
    
        final public void doWork() {
    
        }
    
    }
    
    public class Sub  extends Super{
    
        public void doWork() {  //此行语法报错
    
        }
    
    }
    
    • final修饰的变量:表示常量,该变量只能赋值一次,不能再重新赋值。

    • 基本数据类型:表示的值不能改变

    • 引用数据类型:所引用的地址值不能改变

    final int age = 17;
    
    age = 100;  //此行语法报错
    
    final Dog d = new Dog();
    
    d.setAge(5);  //d的字段值是可以改变的
    
    d = new Dog();  //此行语法报错
    

    1.5. 代码块(了解)

    什么是代码块:直接使用{}括起来的一段代码区域。

    代码块里变量属于局部变量,只在自己所在区域{}内有效。

    存在三种形式:

    • 局部代码块: 直接定义在方法内部的代码块,一般的,不会直接使用局部代码块的,结合if、while、for等关键字使用,表示一块代码区域。
    public class CodeBlockDemo {
    
        public static void main(String[] args) {
    
            System.out.println("begin...");
    
            {
    
                //直接使用代码块,一般不用
    
                int age = 17;
    
            }
    
            System.out.println(age);  //此行报错,超出age作用范围,就不能访问到了
    
            if (100 > 5) {
    
                System.out.println("100 > 5");
    
            }
    
            System.out.println("end...");
    
        }
    
    }
    
    • 初始化代码块(构造代码块):直接定义在类中。每次创建对象的时候都会执行初始化代码块,开发中不使用初始化代码块,即使要做初始化操作,可以直接在构造器中完成即可。

    • 静态代码块:使用static修饰的初始化代码块,当该代码块的类的字节码被加载进JVM,就执行static代码块代码。在开发中,用来做加载资源、加载配置文件等操作。

    分析下面代码执行顺序:

    public class Fish {
    
        {
    
            System.out.println("初始化代码块...");
    
        }
    
        static {
    
            System.out.println("静态代码块...");
    
        }
    
        public Fish() {
    
            System.out.println("构造器");
    
        }
    
        public static void main(String[] args) {
    
            System.out.println("主方法...");
    
            new Fish();
    
            new Fish();
    
        }
    
    }
    

    运行结果:

    静态代码块...
    
    主方法...
    
    初始化代码块...
    
    构造器
    
    初始化代码块...
    
    构造器
    

    1.6. 内部类和匿名内部类(了解)

    什么是内部类,把一个类定义在另一个类的内部,把里面的类称之为内部类,把外面的类称之为外部类。(能认识内部类即可)

    image.png

    内部类可以看作和字段、方法一样,是外部类的成员,而成员可以有static修饰。

    • 静态内部类:使用static修饰的内部类,那么访问内部类直接使用外部类名来访问

    • 实例内部类:没有使用static修饰的内部类,访问内部类使用外部类的对象来访问

    • 局部内部类:定义在方法中的内部类,一般不用

    • 匿名内部类:特殊的局部内部类,适合于仅使用一次使用的类

    对于每个内部类来说,Java编译器会生成独立.class文件。

    • 静态和实例内部类:外部类名$内部类名字

    • 局部内部类:外部类名$数字内部类名称

    • 匿名内部类:外部类名$数字

    1.6.1. 匿名内部类(重点掌握)

    在多态USB的案例中,当新增一种USB规范的设备,此时需要单独使用一个文件来定义一个新的类。

    比如,新增一个USB规范的打印机设备。

    public class Print implements IUSB{
    
        public void swapData() {
    
            System.out.println("打印....");
    
        }
    
    }
    

    把打印机安装在主板上。

    public class USBDemo {
    
        public static void main(String[] args) {
    
            // 创建主板对象
    
            MotherBoard board = new MotherBoard();
    
            // 创建打印机对象
    
            Print p = new Print();
    
            //把打印机安装在主板上
    
            board.plugin(p);
    
        }
    
    }
    

    如果这一个Print类只需要使用一次的话,就完全没有必要单独定义一个Java文件,直接使用匿名内部类来完成。

    匿名内部类,可以使用父类构造器和接口名来完成。

    针对类,定义匿名内部类来继承父类(使用较少):

    new  父类构造器([实参列表]){
    
         //匿名内部类的类体部分
    
    }
    

    针对接口,定义匿名内部类来实现接口(使用较多):

    new  接口名称(){
    
         //匿名内部类的类体部分
    
    }
    

    注意:这里不是根据接口创建对象,而是一种语法而已。

    board.plugin(new IUSB() {
    
        public void swapData() {
    
            System.out.println("打印...打印...");
    
        }
    
    });
    

    其实匿名内部类,底层依然还是创建了一份字节码文件USBDemo$1,其反编译代码为:

    image.png

    若要获得最好的学习效果,需要配合对应教学视频一起学习。需要完整教学视频,请参看https://ke.qq.com/course/272077

    相关文章

      网友评论

          本文标题:Java入门教程-面向对象查漏补缺

          本文链接:https://www.haomeiwen.com/subject/izxggftx.html