JAVA第六课:面向对象(下)

1. 继承

(1)把多个类中相同的属性和行为提取出来,定义到一个类中,然后让这多个类和这一个类产生一个关系,这多个类就具备这一个类的属性和行为了。这种关系叫:继承。

(2)继承如何表示的呢?

Java语言中类的继承是通过extends关键字来实现的,其格式如下:
class 子类名 extends 父类名 {}
class SubClass extends SuperClass { … }
子类可以从父类那里继承所有非private的成员作为自己的成员。
若无extends关键字,则该类默认为java.lang.Object类的子类。
子类的每个对象也是父类的对象(“即是”性质),但父类对象不一定是子类的对象。

class 人类{ ... }
class 男人类 extends 人类{ ... }
class 女人类 extends 人类{ ... }

使用继承过来的成员时,可利用“子类对象.父类成员名”格式进行。
在执行子类的构造方法之前,将先调用父类中没有参数的构造方法,其目的是为了帮助继承自父类的成员做初始化的操作。
严格意义上说,构造方法是不能被继承的,但子类可以调用父类的构造方法。

  • 测试demo
class Person {
    public String name;
    public int age;

    public Person() {
        System.out.println("public Person()");
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("public Person(String name, int age)");
    }
    public void show() {
        System.out.println("name:" + name + ", age:" + age);
    }
}

class Man extends Person {
    public int sex;
    public Man() {
        this.sex = 0;
    }
    public Man(String name, int age) {
        this.name = name;
        this.age = age;
        this.sex = 0;
    }
}

class Woman extends Person {
    private int sex;
    public Woman() {
        this.sex = 1;
    }
    public Woman(String name, int age) {
        this.name = name;
        this.age = age;
        this.sex = 1;
    }
}

public class App {
    public static void main(String[] args) {
        Person p = new Person("AAA", 11);
        p.show();

        Man m1 = new Man("BBB", 12);
        m1.show();

        Woman m2 = new Woman("CCC", 13);
        m2.show();
    }
}

(3)java中的继承特点:

通过类的继承方式,可以不用编写相同的代码就能开发出新的类,即程序代码复用。
子类继承父类的成员变量和方法,同时还可修改、重写和添加父类的成员变量和方法。
被继承的类称为父类、基类或超类(superclass),由继承而得到的类称为子类(subclass)或者派生类。
Java语言中不支持多重继承,所以一个类只能有一个直接父类。
class SubDemo extends Demo{} //ok
class SubDemo extends Demo1,Demo2…//error
java中可以多层继承。(继承体系)
class A{}
class B extends A{}
class C extends B{}
Java语言中有一个名为java.lang.Object的特殊类,所有的类都是直接或间接地继承该类而得到的。

class A {
    public int data_a = 1;
}
class B extends A {
    public int data_b = 2;
}
class C extends B {
    public int data_c = 3;
}

public class App {
    public static void main(String[] args) {
        A a = new A();
        System.out.println("a.data_a = " + a.data_a);
        System.out.println("---------------------");

        B b = new B();
        System.out.println("b.data_a = " + b.data_a);
        System.out.println("b.data_b = " + b.data_b);
        System.out.println("---------------------");

        C c = new C();
        System.out.println("c.data_a = " + c.data_a);
        System.out.println("c.data_b = " + c.data_b);
        System.out.println("c.data_c = " + c.data_c);
        System.out.println("---------------------");
    }
}

(4)java中的继承的好处和弊端

好处:提高了代码的复用性;提高了代码的可维护性;让类与类之间产生了一个关系,是多态的前提。
弊端:让类与类的耦合增强了,这样一个类的改动会直接影响另一个类。

设计原则:高内聚低耦合。

简单的理解:
内聚就是自己完成某件事情的能力。
耦合就是类与类之间的关系。
我们在设计的时候原则是:自己能完成的就不麻烦别人,这样将来别人产生了修改,就对我的影响较小。
由此可见:在开发中使用继承其实是在使用一把双刃剑。

(5)java中的继承的注意事项:

A:私有成员不能被继承
B:构造方法不能被继承,想访问,通过super关键字
C:不能为了部分功能而去使用继承

(6)继承中的成员关系:

成员变量与成员方法
不同名:特别简单,一看就知道用的是谁。
同名:就近原则
访问自己的用this,访问父亲的用super

构造方法
子类的所有构造方法默认都是访问父类的无参构造方法
如果父类没有无参构造方法,怎么办呢? /提问:什么时候没有无参构造?
通过super(…)访问父类带参构造方法
通过this(…)访问本类其他构造方法。(一定要有一个访问了父类的构造方法)
注意:super或者this只能出现一个,并且只能在语句的第一条语句。
为什么呢?
因为子类可能会访问父类的数据,所以,在子类初始化之前,要先把父类数据初始化完毕。

(7)this和super的区别及应用场景

区别
this:本类对象的引用
super:父类存储空间的标识。可以理解为父类对象的引用。

应用场景
成员变量
this.变量 ----- 本类的成员变量
super.变量 ----- 父类的成员变量
构造方法
this(…) ----- 本类的构造方法
super(…) ----- 父类的构造方法
成员方法
this.方法名(…) ---- 本类的成员方法
super.方法名(…) ----父类的成员方法

2. super关键字

  1. 在父类中定义一个成员变量
  2. 在子类中定义一个成员变量和父类中成员变量名称不同,然后再在子类中定义一个方法去访问变量,发现变量名不同,访问非常简单
  3. 在子类中再定义一个成员变量,和父类中的成员变量名称一致,然后继续访问。发现访问的是子类的成员变量。
  4. 如果我要访问父类的成员变量该怎么办呢? 通过回想 this 来引入 super 关键字

super的用法和this很像
this代表本类对应的引用。
super代表父类存储空间的标识(可以理解为父类引用)

用法(this和super均可如下使用)

访问成员变量
this.成员变量
super.成员变量
访问构造方法
this(…)
super(…)
访问成员方法
this.成员方法()
super.成员方法()

继承中构造方法的关系:子类中所有的构造方法默认都会访问父类中空参数的构造方法
为什么呢?
因为子类会继承父类中的数据,可能还会使用父类的数据;
所以,子类初始化之前,一定要先完成父类数据的初始化。
每一个构造方法的第一条语句默认都是:super()

  • demo
class Person {
    public String name;
    public int age;

    public Person() {
        System.out.println("public Person()");
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("public Person(String name, int age)");
    }
    public void show() {
        System.out.println("name:" + name + ", age:" + age);
    }
}

class Man extends Person {
    public int sex;

    public Man() {
        this.sex = 0;
    }
    public Man(String name, int age) {
        super(name, age);
        this.sex = 0;
    }
}

class Woman extends Person {
    private int sex;

    public Woman() {
        this.sex = 1;
    }
    public Woman(String name, int age) {
        super(name, age);
        this.sex = 1;
    }
}

public class App {
    public static void main(String[] args) {
        Person p = new Person("AAA", 11);
        p.show();

        Man m1 = new Man("BBB", 12);
        m1.show();

        Woman m2 = new Woman("CCC", 13);
        m2.show();
    }
}

3. final关键字

final:最终的意思。
作用:可以修饰类,成员变量,成员方法。

特点:
类:类被final修饰,说明该类是最终类,不能被继承。
成员变量:变量被final修饰后,就变成了常量。值不能被修改。
成员方法:方法不能被子类重写。

final修饰局部变量
基本类型:基本类型的值不能变量
引用类型:引用类型的地址值不能改变

final的初始化时机:
A:在定义的时候立即给值。以后在也不能改了。
B:在定义后,构造方法结束前赋值都可以。

final class A {
    public int data_1 = 1;
    public int data_2 = 2;
}

class B {
    public int data_3 = 3;
    public int data_4 = 4;
    final public int data_5 = 5;

    final public void show() {
        System.out.println("data_3 = " + this.data_3);
        System.out.println("data_4 = " + this.data_4);
        System.out.println("data_5 = " + this.data_5);
    }
}

class C extends B {
    public int data_6 = 6;
    // public void show() { } // error
}
// class B extends A { } // error

public class App {
    public static void main(String[] args) {
        C c = new C();
        c.show();
        // c.data_5 = 15;// error
        System.out.println("data_6 = " + c.data_6);
    }
}

面试题:

final修饰局部变量
a:基本类型 ----- 值不能发生改变
b:引用类型 ----- 地址值不能发送改变,对象的内容是可以改变的
final的初始化时机
a:在定义时就赋值
b:在构造方法完毕前赋值

4. 方法重写/override

(1)描述:在子类中,出现了和父类中一模一样的方法声明的现象。
(2)作用:可以使用父类功能,还可以增强该功能。
(3)方法重写的注意事项:

  1. 父类私有方法不能被重写
  2. 子类重写方法的访问权限不能比父类的方法低
  • demo
class Person {
    public String name;
    public int age;

    public Person() {
        System.out.println("public Person()");
    }
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("public Person(String name, int age)");
    }
    public void show() {
        System.out.println("name:" + name + ", age:" + age);
    }
}

class Man extends Person {
    public int sex;

    public Man() {
        this.sex = 0;
    }
    public Man(String name, int age) {
        super(name, age);
        this.sex = 0;
    }
    public void show() {// override
        System.out.println("name:" + name + ", age:" + age + ", sex:" + sex);
    }
}

class Woman extends Person {
    private int sex;

    public Woman() {
        this.sex = 1;
    }
    public Woman(String name, int age) {
        super(name, age);
        this.sex = 1;
    }

    public void show() { // override
        System.out.println("name:" + name + ", age:" + age + ", sex:" + sex);
    }
}

public class App {
    public static void main(String[] args) {
        Person p = new Person("AAA", 11);
        p.show();

        Man m1 = new Man("BBB", 12);
        m1.show();

        Woman m2 = new Woman("CCC", 13);
        m2.show();
    }
}

(4)面试题:

重写override和重载overload的区别?
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求,不能根据返回类型进行区分。
重写(覆盖)的规则:
1、重写方法的参数列表必须完全与被重写的方法的相同,否则不能称其为重写而是重载.
2、重写方法的访问修饰符一定要大于被重写方法的访问修饰符(public>protected>default>private)。
3、重写的方法的返回值必须和被重写的方法的返回一致或者兼容;
4、重写的方法所抛出的异常必须和被重写方法的所抛出的异常一致,或者是其子类;
5、被重写的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行重写;
6、静态方法不能被重写为非静态的方法(会编译出错);
7、父类方法被final时,无论该方法被public、protected及默认所修饰,子类均不能重写该方法。
overload是重载,一般是用于在一个类内实现若干重载的方法,这些方法的名称相同而参数形式不同。
重载的规则:
1、在使用重载时只能通过相同的方法名、不同的参数形式实现。不同的参数类型可以是不同的参数类型,不同的参数个数,不同的参数顺序(参数类型必须不一样);
2、不能通过访问权限、返回类型、抛出的异常进行重载;
3、方法的异常类型和数目不会对重载造成影响。

5. 多态

(1)多态:即多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。
(2)多态的前提:有继承关系、有方法重写、有父类引用指向子类对象

多态的产生:多态是在不同继承关系的类对象,去调用同一函数,产生了不同的行为。

(3)多态中的成员访问特点:

成员变量:编译看左边,运行看左边
成员方法:编译看左边,运行看右边
静态方法:编译看左边,运行看左边
为什么:因为方法有重写,而变量没有,静态方法没有重写一说。
举例:

class Animal {
    public int age = 40;

    public void show() {
        System.out.println("show animal");
    }
    public static void method() {
        System.out.println("method animal");
    }
}

class Dog extends Animal {
    public int age = 20;

    public void show() {
        System.out.println("show dog");
    }
    public static void method() {
        System.out.println("method dog");
    }
}

class App {
    public static void main(String[] args) {
        Animal a = new Dog();
        System.out.println(a.age);
        a.show();
        a.method();
    }
}

输出结果
40 ---- 成员变量:编译看左边,运行看左边
show dog ---- 成员方法:编译看左边,运行看右边
method animal ---- 静态方法:编译看左边,运行看左边

多态的好处
提高了程序的维护性(由继承保证)
提高了程序的扩展性(由多态保证)
多态的弊端:不能访问子类特有功能

那么我们如何才能访问子类的特有功能呢?(多态中的转型)
多态中的转型问题

向上转型:从子到父,父类引用指向子类对象
向下转型:从父到子,父类引用转为子类对象

class Animal {
    public String name;
    public int age;

    public Animal() {}
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat() {
        System.out.println("Animal.eat()");
    }

    public void call() {
        System.out.println("Animall.call()");
    }

}

class Dog extends Animal {
    public Dog() {}
    public Dog(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("Dog.eat()");
    }

    @Override
    public void call() {
        System.out.println("Dog.call()");
    }

    public void lookDoor() {
        System.out.println("Dog.lookDoor: " + name);
    }
}

class Cat extends Animal {
    public Cat() {}
    public Cat(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println("Cat.eat()");
    }

    @Override
    public void call() {
        System.out.println("Cat.call()");
    }
}

public class App {
    public static void main(String[] args) {
        Animal animal = new Dog("aaa", 11);
        Cat cat = new Cat("Cat", 12);
        Dog dog = new Dog("Dog", 13);
        Dog dog2 = (Dog) animal;

        animal.call();  // Dog.call()
        cat.call();     // Cat.call()
        dog.call();     // Dog.call()
        dog.lookDoor(); // Dog.lookDoor: Dog
        dog2.lookDoor();// Dog.lookDoor: aaa

        call(animal);   // Dog.call()
        call(cat);      // Cat.call()
        call(dog);      // Dog.call()
        call(dog2);     // Dog.call()
    }

    private static void call(Animal a) {
        a.call();
    }
}

6. 抽象类

在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。
抽象类特点:抽象类和抽象方法必须用abstract关键字修饰

格式
abstract class 类名 {}
public abstract void eat();
抽象类不一定有抽象方法,有抽象方法的类一定是抽象类
抽象类不能实例化

那么,抽象类如何实例化呢?

按照多态的方式,由具体的子类实例化,其实这也是多态的一种,抽象类多态。
抽象类的子类:要么是抽象类,要么重写抽象类中的所有抽象方法

成员变量:可以是变量,也可以是常量
构造方法:有构造方法,但是不能实例化

那么,构造方法的作用是什么呢?
用于子类访问父类数据的初始化

成员方法
可以有抽象方法,限定子类必须完成某些动作
也可以有非抽象方法,提高代码复用性

  • 抽象类:demo1

public class App {
	public static void main(String[] args) {
//		A a = new A(); // error -- 抽象类妄想实例化对象,不可行
//		B b = new B(); // error
		C c = new C(); // ok
		c.eat();
		c.call();
		c.show();
	}
}

abstract class A{ // 抽象类
	public abstract void eat(); // 抽象方法
	public abstract void call();
	
	public void show() {
		System.out.println("A.show()");
	}
}
abstract class B extends A{ } // 抽象类继承抽象类,还是抽象的

class C extends A{ // 子类继承抽象类,并重写所有抽象方法 --- 可用来实例化对象
	@Override
	public void eat() {
		System.out.println("C.eat()");
	}
	@Override
	public void call() {
		System.out.println("C.call()");
	}
}
  • 抽象类demo2
abstract class Animal {
    public String name;
    public int age;

    public Animal() {}
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public void show() {
        System.out.println("name:" + name + ", age:" + age);
    }
}

class Cat extends Animal {
    public Cat() {}
    public Cat(String name, int age) {
        super(name, age);
    }
    @Override
    public void show() {
        System.out.println("Cat.show()");
        super.show();
    }
}

public class App {
    public static void main(String[] args) {
        // Animal animal = new Animal("AAA", 11);// error
        Cat cat = new Cat("BBB", 12);
        cat.show();
    }
}
  • 抽象方法:demo

子类要实现父类的抽象方法

abstract class Animal {
    public String name;
    public int age;

    public Animal() {}
    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }
    abstract public void show(); // 抽象方法
}

class Cat extends Animal {
    public Cat() {}
    public Cat(String name, int age) {
        super(name, age);
    }
    public void show() { // 实现抽象方法
        System.out.println("Cat.show()");
    }
}

public class App {
    public static void main(String[] args) {
        // Animal animal = new Animal("AAA", 11);// error
        Cat cat = new Cat("BBB", 12);
        cat.show();
    }
}

三个小问题:

  1. 抽象类的非抽象方法有什么用?抽象方法有什么用?
    抽象类的抽象方法:用于限定子类必须完成某些动作
    抽象类的非抽象方法:用于提高代码的复用性

  2. 一个类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
    可以。为了不让别人创建对象。

  3. abstract不能和哪些关键字共存
    final:final修饰的方法不能被重写,而abstract修饰的方法要求必须被重写。
    private:private修饰的方法不能被重写,而abstract修饰的方法要求必须被重写。
    static:static修饰的方法可以通过类名调用,而abstract修饰的方法是没有方法体的,调用一个没有方法体的方法是没有任何意义的,所以不能共存。

如下举例:

abstract class Student {
	public final abstract void show1();	//error
	private abstract void show2();		//error
	public static abstract void show3();//error
}

7. 接口

为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,将来需要的时候,只需要把这些额外功能实现即可。

接口特点:接口用关键字interface表示
格式:interface 接口名 {}
类实现接口用implements表示
格式:class 类名 implements 接口名 {}

接口不能实例化,那么,接口如何实例化呢?
按照多态的方式,由具体的子类实例化。其实这也是多态的一种,接口多态。

interface Animal {
    public void eat();
    public void call();
}

class Cat implements Animal {
    @Override
    public void eat() {
        System.out.println("Cat.eat()");
    }

    @Override
    public void call() {
        System.out.println("Cat.call()");
    }
}
interface Dog extends Animal { // 接口也可以继承
    public void lookDoor();
}
public class App {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.eat();
        cat.call();
    }
}

接口的子类:要么是抽象类;要么重写接口中的所有抽象方法
接口成员变量:只能是常量;默认修饰符 public static final
构造方法:没有,因为接口主要是扩展功能的,而没有具体存在
成员方法:只能是抽象方法;默认修饰符 public abstract

接口可以使用多继承

interface A {
    public void showA();
}

interface B {
    public void showB();
}

interface C extends A, B { // 接口多继承
    public void showC();
}

class D implements C {
    @Override
    public void showA() {
        System.out.println("showA()");
    }

    @Override
    public void showB() {
        System.out.println("showB()");
    }
    // Java SE5新增加@Override注解,不是关键字,当覆写(重写)某个方法时,可以选择添加或不添加这个注解
    @Override
    public void showC() {
        System.out.println("showC()");
    }

    public void showD() {
        System.out.println("showD()");
    }
}

public class App {
    public static void main(String[] args) {
        D a = new D();
        a.showA();
        a.showB();
        a.showC();
        a.showD();
    }
}

类和接口的关系:
类与类:继承关系,只能单继承,但是可以多层继承
类与接口:实现关系,可以单实现,也可以多实现。还可以在继承一个类的同时实现多个接口
接口与接口:继承关系,可以单继承,也可以多继承
成员区别
抽象类:变量,常量;有抽象方法;抽象方法,非抽象方法
接口:常量;抽象方法
关系区别
类与类:继承,单继承
类与接口:实现,单实现,多实现
接口与接口:继承,单继承,多继承
设计理念区别
抽象类:被继承体现的是:"is a"的关系。共性功能
接口:被实现体现的是:"like a"的关系。扩展功能
形式参数:基本类型、引用类型
返回值类型:基本类型、引用类型

抽象类和接口类型作为形式参数。

形式参数
类:需要的是该类的对象
抽象类:需要的是该抽象类的子类对象
接口:需要的是接口的子类对象

具体类作为形式参数:需要的是该类的对象

class Student {
    public void show() {
        System.out.println("Student.show");
    }
}

class StudentDemo {
    public void method(Student s) {
        s.show();
    }
}

class App {
    public static void main(String[] args) {
        StudentDemo sd = new StudentDemo();
        Student s = new Student();
        sd.method(s);
    }
}

抽象类作为形式参数:需要的是该抽象类的子类对象(抽象类多态)

abstract class Person {
    public abstract void show();
}

class Student extends Person {
    public void show() {
        System.out.println("Student.show");
    }
}

class PersonDemo {
    public void method(Person p) {
        p.show();
    }
}

class App {
    public static void main(String[] args) {
        PersonDemo pd = new PersonDemo();
        Person p = new Student();
        pd.method(p);
    }
}

接口作为形式参数:需要的是该接口的实现类对象 (接口多态)

interface Animall {
    public abstract void call();
}

class Cat implements Animall {
    @Override
    public void call() {
        System.out.println("Cat.call()");
    }
}

class Demo {
    public void method(Animall animall) {
        animall.call();
    }
}

public class App {
    public static void main(String[] args) {
        Demo demo = new Demo();
        Animall animall = new Cat();
        demo.method(animall);
    }
}

返回值的问题
基本类型:返回什么就用什么接收。
引用类型
类:其实返回的是该类的对象
抽象类:其实返回的是该类的子类对象
接口:其实返回的是该接口的子类对象

具体类作为返回值类型:返回的是该类的对象

class Student {
    public void show() {
        System.out.println("Student.show()");
    }
}

class StudentDemo {
    public Student getStudent() {
        // Student s = new Student();
        // return s;
        return new Student();
    }
}

class App {
    public static void main(String[] args) {
        // 如何测试呢?
        // 原本我可以直接通过Student创建对象,调用功能
        // 但是现在不让这样做,怎么办呢?
        StudentDemo sd = new StudentDemo();
        Student s = sd.getStudent();
        s.show();
    }
}

抽象类作为返回值类型:返回的是该类的子类对象

abstract class Person {
    public abstract void show();
}

class Student extends Person {
    public void show() {
        System.out.println("Student.show()");
    }
}

class PersonDemo {
    public Person getPerson() {
        // Person p = new Student();
        // return p;
        return new Student();
    }
}

class App {
    public static void main(String[] args) {
        PersonDemo pd = new PersonDemo();
        Person p = pd.getPerson();
        p.show();
    }
}

接口作为返回值类型:返回的是接口的实现类对象

interface Person {
    public void show();
}

class Student implements Person {
    public void show() {
        System.out.println("Student.show()");
    }
}

class PersonDemo {
    public Person getPerson() {
        // Person p = new Student();
        // return p;
        return new Student();
    }
}

class App {
    public static void main(String[] args) {
        PersonDemo pd = new PersonDemo();
        Person p = pd.getPerson();
        p.show();
    }
}

链式编程的案例演示

new PersonDemo().getPerson().show();

8. 包

包,其实就是文件夹
作用:对类进行分类管理
包的划分(举例):
学生的增加,删除,修改,查询
老师的增加,删除,修改,查询
以及以后可能出现的其他的类的增加,删除,修改,查询
划分依据:按照模块和功能分。

定义包的格式
package 包名;
多级包用.分开即可

注意事项:
package语句必须是程序的第一条可执行的代码
package语句在一个java文件中只能有一个
如果没有package,默认表示无包名

带包的类的编译和运行
手动式
a:javac编译当前类文件。
b:手动建立包对应的文件夹。
c:把a步骤的class文件放到b步骤的最终文件夹下。
d:通过java命令执行。注意了:需要带包名称的执行
java cn.test.HelloWorld
自动式
a:javac编译的时候带上-d即可
javac -d . HelloWorld.java
b:通过java命令执行。和手动式一样

导包

每次使用不同包下的类的时候,都需要加包的全路径,比较麻烦。
这个时候,java就提供了导包的功能。

导包格式:import 包名;
注意:
这种方式导入是到类的名称,虽然可以最后写*,但是不建议。
package,import,class有没有顺序关系(面试题)

权限修饰符(1代表可访问)

类型publicprotected默认private
同一类中1111
同一包子类,其他类111
不同包,子类11
不同包,其他类1

类及其组成可以用的修饰符
类:默认,public,final,abstract;自己定义:public居多
成员变量:四种权限修饰符均可,final,static;我们自己定义:private居多
构造方法:四种权限修饰符均可,其他不可;我们自己定义:public 居多
成员方法:四种权限修饰符均可,fianl,static,abstract;我们自己定义:public居多

9. 内部类

把类定义在其他类的内部,这个类就被称为内部类。
举例:在类A中定义了一个类B,类B就是内部类。

内部类的访问特点:
内部类可以直接访问外部类的成员,包括私有。
外部类要访问内部类的成员,必须创建对象。

内部类位置
按照内部类在类中定义的位置不同,可以分为如下两种格式:
成员位置(成员内部类)
局部位置(局部内部类)

外界如何创建对象
外部类名.内部类名 对象名 = 外部类对象.内部类对象;

package com.baidu;

public class A {
	public int a = 1;
	int b = 1;
	protected int c = 1;
	private int d = 1;
	
	public static void main(String[] args) {
		show();
		A.B b=  new A().new B();
		b.show();
	}
	
	class B{
		public void show() {
			System.out.println("A:a="+a+", b="+b+", c="+c+", d="+d);
			System.out.println("A.B.show()");
		}
	}
	
	public static void show() {
		System.out.println("A.show()");
	}
}

一般来说,在实际开发中是不会这样使用的,因为一般内部类就是不让外界直接访问的。

成员内部的常见修饰符
private 为了保证数据的安全性
static 为了让数据访问更方便
被静态修饰的成员内部类只能访问外部类的静态成员
内部类被静态修饰后的方法
静态方法
非静态方法
1:非静态的成员内部类,成员只能是非静态的。
2:内部类被静态修饰后的方法有静态和非静态之分。他们的访问和不用静态是不一样的。
访问非静态方法:外部类名.内部类名 对象名 = new 外部类名.内部类名();
访问静态方法:上面创建的对象访问,或者外部类名.内部类名.方法名();

局部内部类
可以直接访问外部类的成员
可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能
局部内部类访问局部变量的注意事项:
必须被final修饰? 为什么呢?
因为局部变量会随着方法的调用完毕而消失,这个时候,
局部对象并没有立马从堆内存中消失,还要使用那个变量。
为了让数据还能继续被使用,就用fianl修饰,这样在堆内存里面存储的其实是一个常量值。通过反编译工具可以看一下。

匿名内部类
就是内部类的简化写法。
前提:存在一个类或者接口
这里的类可以是具体类也可以是抽象类。
格式:new 类名或者接口名() {重写方法;}
本质:是一个继承了类或者实现了接口的子类匿名对象
1:通过new去分析,结果是一个对象。
2:如果类是抽象类,或者new后面是接口,所以整体应该是子类对象。
3:又由于没有名字,所以,整体是一个匿名对象。
加入方法有多个,如何调用呢?
方式1:每一种格式调用一个,太麻烦
方式2:用类或者接口接收该子类对象,多态思想

面试题

1.Override 和Overload 的区别? Overload 能改变返回值类型吗?
Override:重写
Overload:重载
方法重写:子类中出现和父类中一模一样的方法声明的现象。
方法重载:同一个类中出现的方法名相同,参数列表不同的现象。
Overload能改变返回值类型,因为它和返回值类型无关。

2.this 关键字和 super 关键字分别代表什么? 以及他们各自的使用场景和作用。
this:本类对象的引用
super:父类存储空间的标识。(可以理解为父类对象的引用)
使用场景:
成员变量:
this.变量 本类的成员变量
super.变量 父类的成员变量
构造方法:
this(…) 本类的构造方法
super(…) 父类的构造方法
成员方法:
this.方法名(…) 本类的成员方法
super.方法名(…) 父类的成员方法

3.final关键字在修饰变量的时候有什么特性
final修饰局部变量:
在方法内部,该变量不可以被改变
在方法声明上,分别演示基本类型和引用类型作为参数的情况
基本类型,是值不能被改变
引用类型,是地址值不能被改变
final修饰变量的初始化时机:
在对象构造完毕前即可

4.看程序写结果(先判断有没有问题,如果没有,写出结果)

4.1 父类引用指向子类对象,调用子类存在,但父类不存在的方法

class Fu{
	public void show(){
		System.out.println("fu show");
	}
}

class Zi extends Fu{
	public void show(){
		System.out.println("zi show");
	}

	public void method(){
		System.out.println("zi method");
	}
}
class Test{
	public static void main(String[] args){
		Fu f = new Zi();
		f.method();
	}
}

4.2 充满爱情的苦

class A {
    public void show() {
        show2();
    }

    public void show2() {
        System.out.println("我");
    }
}

class B extends A {
    public void show2() {
        System.out.println("爱");
    }
}

class C extends B {
    public void show() {
        super.show();
    }

    public void show2() {
        System.out.println("你");
    }
}

public class App {
    public static void main(String[] args) {
        A a = new A();
        a.show();

        A b = new B();
        b.show();

        B c = new C();
        c.show();
    }
}

5.按照要求,补齐代码
要求:在控制台输出”HelloWorld”

interface Inter { void show(); }
class Outer { //补齐代码 }
class OuterDemo {
    public static void main(String[] args) {
	      Outer.method().show();
	  }
}

参考答案如下:

interface Inter { void show(); }

class Outer { 
	//补齐代码
	public static Inter method() {
		return new Inter() {
			public void show() {
				System.out.println("HelloWorld");
			}
		};
	}
}

class OuterDemo {
	public static void main(String[] args) {
		Outer.method().show();
/*
Outer.method():类名能够直接调用方法,说明该方法是静态的。
Outer.method().show():这种用法叫链式编程,调用show()方法之前的内容应该是一个对象
*/
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值