面向对象(下)

目录

1. 继承

1.1 概述

1.2 继承的优缺点

1.2.1 优点

1.2.2 缺点

1.3 Java中继承的特点

1.4 Java中继承的注意事项

1.5 继承中类的各组成部分关系

1.5.1 继承中成员变量之间的关系

1.5.2 继承中构造方法之间的关系

1.5.3 继承中成员方法之间的关系

1.6 方法重写

1.6.1 概述

1.6.2 使用特点

1.6.3 注意事项

1.7 final关键字

1.7.1 概述

1.7.2 特点

1.7.3 两个问题

2. 多态

2.1 多态的概述

2.2 多态的前提和体现

2.3 多态中的成员访问特点

2.3.1 成员变量

2.3.2 构造方法

2.3.3 成员方法

2.3.4 静态方法

2.4 多态的利弊

2.5 多态中的转型问题

2.5.1 向上转型

2.5.2 向下转型

2.6 多态的练习

3. 抽象类

3.1 抽象类的概述

3.2 抽象类的特点

3.3 抽象类的成员特点

4. 接口

4.1 概述

4.2 接口的特点

4.3 接口的成员特点

4.2 类与类、类与接口、接口与接口的关系

4.2.1 类与类的关系

4.2.2 类与接口的关系

4.2.3 接口与接口的关系

4.3 形式参数和返回值的问题

5. 包和导包

5.1 包的概述

5.1.1 概念

5.1.2 作用

5.2 包的定义格式及注意事项

5.2.1 包的定义格式

5.2.2 注意事项

5.3 带包的类的编译和运行

5.4 导包

5.4.1 概述

5.4.2 导包格式

6. 权限修饰符

6.1 四种权限修饰符

6.2 类及其组成常用的修饰符

7. 内部类

7.1 概述

7.2 内部类的访问特点

7.3 内部类的分类

7.4 成员内部类

7.5 局部内部类

7.6 匿名内部类



1. 继承

1.1 概述

多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。

单独的这个类称为父类,基类或者超类;这多个类可以称为子类或者派生类。 有了继承以后,我们定义一个类的时候,可以在一个已经存在的类的基础上,还可以定义自己的新成员。

通过extends关键字可以实现类与类的继承

格式:class 子类名 extends 父类名 {}  

案例1:用继承改进学生老师案例

//多个类同属性同行为的一般写法
//学生类
class Student{
	public void eat(){
		System.out.println("吃饭");
	}
	
	public void sleep(){
		System.out.println("睡觉");
	}
}

//老师类
class Teacher{
	public void eat(){
		System.out.println("吃饭");
	}
	
	public void sleep(){
		System.out.println("睡觉");
	}
}

//测试类
class ExtendsDemo{
	public static void main(String[] args){
		//创建学生类对象
		Student s = new Student();
		//通过对象调用学生类中的方法
		s.eat();
		s.sleep();
		System.out.println("-----");
		
		//创建老师类对象
		Teacher t = new Teacher();
		t.eat();
		t.sleep();
	}
}


//用继承改进
//父类
class Person{
	public void eat(){
		System.out.println("吃饭");
	}
	
	public void sleep(){
		System.out.println("睡觉");
	}
}

//子类
class Student extends Person{}

class Teacher extends Person{}


//测试类
class ExtendsDemo{
	public static void main(String[] args){
		//创建学生类对象
		Student s = new Student();
		//通过对象调用学生类中的方法
		s.eat();
		s.sleep();
		System.out.println("-----");
		
		//创建老师类对象
		Teacher t = new Teacher();
		t.eat();
		t.sleep();
	}
}

1.2 继承的优缺点

1.2.1 优点

  1. 提高了代码的复用性——多个类相同的成员可以放到同一个类中
  2. 提高了代码的维护性——如果功能的代码需要修改,修改一处即可
  3. 让类与类之间产生了关系,是多态的前提。

1.2.2 缺点

类与类之间产生了关系,这也是继承的一个弊端:类的耦合性很强

开发原则:低耦合,高内聚

解释:耦合——类与类之间的关系;内聚——自己完成某件事情的能力

1.3 Java中继承的特点

1. Java只支持单继承,不支持多继承

即,一个类只能继承一个父类,不能有多个父类。有的语言是可以多继承的,格式为:extends 父类1,父类2,……

2. Java支持多层继承(继承体系)

//格式:
class A{}
class B extends A{}
class C extends B{}

//在C类中创建对象,可以通过对象直接调用B类和A类中的方法

1.4 Java中继承的注意事项

  1. 子类只能继承父类所有非私有的成员(成员方法和成员变量)——也体现了另一个弊端:打破了封装性
  2. 子类不能继承父类的构造方法,但是可以通过super(后面讲)关键字去访问父类构造方法。
  3. 不要为了部分功能而去继承 ,继承中类之间体现的是:”is a”的关系,即子类是父类的一种

1.5 继承中类的各组成部分关系

1.5.1 继承中成员变量之间的关系

  • 子类中的成员变量的名称和父类中成员变量不一样
  • 子类中的成员变量的名称和父类中成员变量一样时,其值采用就近原则

名称一样时,在子类方法中访问一个变量的查找顺序:

  1. 首先在子类方法的局部范围找,有就使用;
  2. 然后在子类的成员范围找 ,有就使用;
  3. 最后在父类成员范围找(不能访问到父类局部范围,因为方法不调用不执行) ,有就使用;
  4. 如果还是没有就报错

super关键字和this关键字的区别

案例2:this和super的应用和输出区别

//this和super的区别

//父类
class Father{
	int num = 10;
}

//子类
class Son extends Father{
	int num = 20;
	
	//show方法
	public void show(){
		int num = 30;
		System.out.println(num);//输出30
		System.out.println(this.num);//输出20
		System.out.println(super.num);//输出10
	}
}

class ExtendsDemo1{
	public static void main(String[] args){
		int num = 30;
		//创建子类对象
		Son s = new Son();
		//调用show方法
		s.show();
	}
}

this:代表本类对应的引用

super:代表父类存储空间的标识(可以理解为父类引用)

this  和  super  的使用
 this解释super解释
访问成员变量this.成员变量调用本类的成员方法super.成员变量调用父类的成员变量
访问构造方法this(...)调用本类的构造方法,()里为参数super(...)调用父类的构造方法,()里为参数
访问成员方法this.成员方法()调用本类的成员方法super.成员方法()调用父类的成员方法

1.5.2 继承中构造方法之间的关系

  • 子类中所有的构造方法默认都会访问父类中空参数的构造方法

案例3:子类构造方法和父类构造方法的关系

//子类构造方法和父类构造方法的关系
//父类
class Father{
	//父类无参构造方法,构造方法的方法名与该类的类名相同
	public Father(){
		System.out.println("这是父类的无参构造方法");
	}
	
	//父类带参构造方法
	public Father(String name){
		System.out.println("这是父类的带参构造方法");
	}
}

//子类
class Son extends Father{
	//子类无参构造方法,构造方法的方法名与该类的类名相同
	public Son(){
                //super();//默认调用父类的无参构造方法
		System.out.println("这是子类的无参构造方法");
	}
	
	//子类带参构造方法
	public Son(String name){
                //super();//默认调用父类的无参构造方法
		System.out.println("这是子类的带参构造方法");
	}
}

class ExtendsDemo2{
	public static void main(String[] args){
		//创建子类对象
		Son s = new Son();
		
		System.out.println("-----------");
		
		//创建带参的子类对象
		Son s1 = new Son("卡卡西");
	}
}输出:
这是父类的无参构造方法
这是子类的无参构造方法
-----------
这是父类的无参构造方法
这是子类的带参构造方法

原因:

因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化

注意:

子类每一个构造方法的第一条语句默认都是:super();

注意事项:

1. 子类的构造方法默认会去访问父类的无参构造方法
                是为了子类访问父类数据的初始化

2. 父类中如果没有无参构造方法(只给了带参构造方法),怎么办?
                a. 子类通过super去明确调用带参构造
                b. 子类通过this调用本身的其他构造,但是一定会有一个去访问了父类的构造,让父类提供无参构造

练习题1:

//以下代码的输出结果是?
class Fu{
	public int num = 10;
	public Fu(){
		System.out.println("fu");
	}
}
class Zi extends Fu{
	public int num = 20;
	public Zi(){
		System.out.println("zi");
	}
	public void show(){
		int num = 30;
		System.out.println(num);
		System.out.println(this.num);
		System.out.println(super.num);
	}
}
class Test {
	public static void main(String[] args) {
		Zi z = new Zi();
		z.show();
	}
}
//输出结果:
fu
zi
30
20
10

练习题2:

要点:

  1. 一个类的静态代码块、构造代码块、构造方法执行流程——静态代码块 > 构造代码块 > 构造方法
  2. 静态的内容是随着类的加载而加载;
  3. 子类初始化之前会进行父类的初始化。
class Fu {
	static {
		System.out.println("静态代码块Fu");
	}

	{
		System.out.println("构造代码块Fu");
	}

	public Fu() {
		System.out.println("构造方法Fu");
	}
}

class Zi extends Fu {
	static {
		System.out.println("静态代码块Zi");
	}
	
	{
		System.out.println("构造代码块Zi");
	}

	public Zi() {
		System.out.println("构造方法Zi");
	}
}

class Test1 {
	public static void main(String[] args) {
		Zi z = new Zi();
	}
}
//输出结果
静态代码块Fu
静态代码块Zi
构造代码块Fu
构造方法Fu
构造代码块Zi
构造方法Zi

练习题3:

要点:

  1. 成员变量类型(基本型和引用型)
  2. 一个类的初始化过程
    1. 成员变量的初始化(默认初始化→显示初始化→构造方法初始化)
  3. 子父类的初始化(又称分层初始化)
    1. 先进行父类初始化,再进行子类初始化
class X {
	Y b = new Y();
	X() {
		System.out.print("X");
	}
}

class Y {
	Y() {
		System.out.print("Y");
	}
}

public class Z extends X {
	Y y = new Y();
	Z() {
		System.out.print("Z");
	}
	public static void main(String[] args) {
		new Z(); 
	}
}
//输出结果:
YXYZ

1.5.3 继承中成员方法之间的关系

  • 子类中的方法和父类中的方法声明不一样
  • 子类中的方法和父类中的方法声明一样时,先看子类中有无,有就使用;没有就在父类中找

案例4:

class Father{
	public void show(){
		System.out.println("Show Father");
	}
}
class Son extends Father{
	public void method(){
		System.out.println("method Son");
	}
	public void show(){
		System.out.println("Show Son");
	}
}
class ExtendsDemo3{
	public static void main(String[] args){
		Son s = new Son();
		s.show();
		s.method();
	}
}
输出结果:
Show Son
method Son

1.6 方法重写

1.6.1 概述

子类中出现了和父类中一模一样的方法声明,也被称为方法覆盖,方法复写 

1.6.2 使用特点

  1. 如果方法名不同,就调用对应的方法
  2. 如果方法名相同,最终使用的是子类自己的

1.6.3 注意事项

  1. 父类中私有方法不能被重写
  2. 子类重写父类方法时,访问权限不能更低
  3. 父类静态方法,子类也必须通过静态方法进行重写(这个算不上方法重写)

两个思考题:
1. Override和Overload的区别?Overload是否可以改变返回值类型?

答:

  • 方法重写——在子类中出现和父类一模一样的方法声明的现象
  • 方法重载——同一个类中出现的方法名相同,参数列表不同的现象,能改变返回值,因为与返回值类型无关

2. this和super的区别和各自的作用?

  • this——代表当前类的对象的引用
  • super——代表父类存储空间的标识

作用见1.5.3节的表格

1.7 final关键字

1.7.1 概述

final关键字是最终的意思,可以修饰类,成员变量,成员方法

1.7.2 特点

  • 修饰类——被修饰的类为最终类,最终类不能被继承(不能有子类)
  • 修饰方法——被final修饰的方法不能被重写(覆盖)
  • 修饰变量——被修饰的变量不能被重新赋值,其实就是常量(为自定义常量,之前学的为字面值常量)

1.7.3 两个问题

1. final修饰局部变量的问题

  • 在方法内部,该变量不可以被改变
  • 在方法声明上,参数类型
    • 为基本类型,值不能被改变,
    • 为引用类型,地址值不能被改变 

2. final修饰变量的初始化时机

  • final修饰的变量只能赋值一次
  • 在对象构造完毕前即可

2. 多态

2.1 多态的概述

某一个对象(事物),在不同时刻表现出来的不同状态

举例:水的不同状态

2.2 多态的前提和体现

前提:

  1. 要有继承关系
  2. 要有方法重写
  3. 要有父类引用指向子类对象( 父 f = new 子(); )

2.3 多态中的成员访问特点

2.3.1 成员变量

编译看左边,运行看左边

2.3.2 构造方法

创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化

2.3.3 成员方法

编译看左边,运行看右边(方法重写覆盖了)

2.3.4 静态方法

编译看左边,运行看左边(静态随着类的加载而加载)

2.4 多态的利弊

利:

  1. 提高了代码的维护性(由继承保证)
  2. 提高了代码的扩展性(由多态保证)

弊:

  1. 不能使用子类中的特有功能

2.5 多态中的转型问题

要想使用子类中的特有功能,有两种方法:

  1. 创建子类对象调用方法即可(占内存)
  2. 将父类的引用强制转换为子类的引用(向下转型)——Zi z = (Zi) f;

2.5.1 向上转型

Fu f = new Zi();//左边为大类,右边为小类

2.5.2 向下转型

Zi z = (Zi) f;——要求该f必须是能转换为Zi的

2.6 多态的练习

案例:猫狗案例

//猫狗案例
class Animal{
	public void eat(){
		System.out.println("吃饭");
	}
}

//狗类继承动物类
class Dog extends Animal{
	public void eat(){
		System.out.println("狗吃肉");
	}
	public void lookDoor(){
		System.out.println("狗看门");
	}
}

//猫继承动物类
class Cat extends Animal{
	public void eat(){
		System.out.println("猫吃鱼");
	}
	public void playGame(){
		System.out.println("猫玩捉迷藏");
	}
}

//测试类
class DuoTaiTest{
	public static void main(String[] args){
		//Animal类中的引用a指向Dog类,定义为狗
		Animal a = new Dog();
		a.eat();
		System.out.println("-------------");
		
		//创建Dog中的对象d,将a强制转换使用Dog类中的特有功能,还原成狗
		Dog d = (Dog) a;
		d.eat();
		d.lookDoor();
		System.out.println("-------------");
		
		//定义为猫
		a = new Cat();
		a.eat();
		System.out.println("-------------");
		
		//还原为猫
		Cat c = (Cat)a;
		c.eat();
		c.playGame();
	}
}
输出:
狗吃肉
-------------
狗吃肉
狗看门
-------------
猫吃鱼
-------------
猫吃鱼
猫玩捉迷藏

3. 抽象类

3.1 抽象类的概述

把多个共性的东西提取到一个类中,这是继承的做法。但是,这多个共性的东西,在有些时候,方法声明一样,但是方法体。也就是说,方法声明一样,但是每个具体的对象在具体实现的时候内容不一样。所以,我们在定义这些共性的方法的时候,就不能给出具体的方法体。
       而一个没有具体的方法体的方法是抽象的方法(注意没有方法体和空方法体的区别)。
       在一个类中如果有抽象方法,该类必须定义为抽象类。

3.2 抽象类的特点

  • 抽象类和抽象方法必须用abstract关键字修饰
格式:
abstract class 类名 {}
public abstract void eat(); 
  • 抽象类不一定有抽象方法,有抽象方法的类必须是抽象类
  • 抽象类不能实例化,因为它不是具体的。按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态 
  • 抽象类的子类,要么是抽象类(不重写抽象方法),要么重写抽象类中的所有抽象方法(此时子类为具体类)

3.3 抽象类的成员特点

成员变量

既可以是变量,又可以是常量

构造方法

有构造方法,用于子类访问父类数据的初始化

成员方法

既可以是抽象方法,也可以是非抽象方法

抽象方法——强制要求子类做的事

非抽象方法——子类继承的事情,提高代码复用性

4. 接口

4.1 概述

为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现

4.2 接口的特点

  • 接口用关键字interface修饰
格式:interface 接口名 {}
  • 类实现接口用implements修饰
格式:class 类名 implements 接口名 {}
  • 接口不能实例化(用多态的方式来实现实例化)

多态的三种方式:

  1. 具体类多态(几乎没有)
  2. 抽象类多态
  3. 接口多态(最常见)
  • 接口的子类
    • 是一个抽象类,意义不大
    • 是一个具体类,这个类必须重写接口中的所有抽象方法

案例1:

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

*/
//猫狗案例
//定义动物培训接口
interface AnimalTrain {
	//定义抽象类,无方法体
	public abstract void jump();
	
}

//抽象类实现接口,可以,但是意义不大
abstract class Dog implements AnimalTrain {
	
} 

//具体类实现接口
class Cat implements AnimalTrain {
	//重写方法
	public void jump(){
		System.out.println("小猫钓鱼");
	}
}
class InterfaceDemo {
	public static void main(String[] args){
		/*
		在类AnimalTrain中创建对象at报错,因为AnimalTrain是抽象类,无法实例化
		AnimalTrain at = new AnimalTrain();
		at.jump();
		*/
		AnimalTrain at = new Cat();
		at.jump();
	}
}

4.3 接口的成员特点

成员变量

  1. 接口中的变量默认为常量,且是静态的
  2. 有默认修饰符:public static final
  3. 默认修饰符建议自己手动给出

构造方法

  1. 接口没有构造方法,因为接口主要功能为扩展,没具体存在
  2. 其实现接口的具体类有构造方法,默认继承于Object类
  • 所有的类都默认继承自一个类:Object

成员方法

  1. 只能是抽象方法
  2. 默认修饰符:public abstract
  3. 默认修饰符建议自己手动给出

案例2:

//接口的成员特点
//定义Inter接口
interface Inter {
	//定义成员变量
	public int num = 10;
	public final int num1 = 20;
	
	//给接口写构造方法,编译报错
	//因为接口没有构造方法
	//public Inter(){}//错误: 需要<标识符>
	
	//写成员方法
	//public void show(){}//错误: 接口抽象方法不能带有主体
	abstract void show();//默认权限为public
}

/*
//具体类InterImpl实现接口
//开发中,接口名+Impl这种格式是接口的实现类格式
class InterImpl implements Inter {
	//给实现类写构造方法,编译不报错。因为所有的类都默认继承自一个类:Object
	public InterImpl(){
		//访问父类构造方法
		super();
	}
}
*/

//具体类InterImpl实现接口(默认继承于Object类)
class InterImpl extends Object implements Inter {
	//给实现类写构造方法,编译不报错
	//因为所有的类都默认继承自一个类:Object
	public InterImpl(){
		//访问父类构造方法
		super();
	}
	//具体类中的成员方法
	public void show(){}//不写public报错:正在尝试分配更低的访问权限; 以前为public
}

//测试类
class InterfaceDemo1 {
	public static void main(String[] args) {
		//创建对象i
		Inter i = new InterImpl();
		
		//多态中访问成员变量是访问的左边(只有成员方法是访问的右边,因为方法重写)
		System.out.println(i.num);//输出10
		System.out.println(i.num1);//输出20
		
		//i.num = 100;// 错误: 无法为最终变量num分配值
		//i.num1 = 200;// 错误: 无法为最终变量num1分配值
		
		System.out.println(Inter.num);//通过接口名字访问变量,输出10
		System.out.println(Inter.num1);//通过接口名字访问变量,输出20
		
	}
}

4.2 类与类、类与接口、接口与接口的关系

4.2.1 类与类的关系

继承关系(extends):只能单继承,可以多层继承

4.2.2 类与接口的关系

实现关系(interface定义接口,implements实现接口):

可以单实现,也可以多实现(接口之间用逗号隔开即可,调用的时候注意方法与接口对应)

还可以在继承一个类的同时实现多个接口(联想默认继承类Object)

4.2.3 接口与接口的关系

继承关系,可以单继承,也可以多继承

抽象类和接口的区别:

A:成员区别
    抽象类: 
        成员变量:可以是常量,也可以是变量
        构造方法:有
        成员方法:可以使抽象,也可以是非抽象

    接口:
        成员变量:只能是常量
        成员方法:只能是抽象的

B:关系区别
    类与类:
        继承,只能单继承,不能多继承

    类与接口:
        实现,可以单实现,也可以多实现

    接口与接口:
        继承,可以单继承,也可以多继承

C:设计理念区别
    抽象类:
        被继承体现的是is a的关系
        抽象类中定义的是该继承体系中的共性功能
    接口:
        被继承体现的是like a的关系
        接口中定义的是该继承体系中的扩展功能

4.3 形式参数和返回值的问题

形式参数:

  1. 基本类型
  2. 引用类型(类、抽象类、接口)

案例1:类名作为形参,需要的是该类的对象

class Student{
	public void study(){
		System.out.println("好好学习,天天向上");
	}
}

class StudentDemo{
	public void method(Student s){
		s.study();
	}
}
//测试类
class StudentTest{
	public static void main(String[] args){
		//测试Student中的study方法,在Student类中创建对象s
		Student s = new Student();
		//通过该类中的对象s调用study方法
		s.study();
		
		//测试StudentDemo中的method方法,在StudentDemo类中创建对象ss
		StudentDemo sd = new StudentDemo();
		//在Student类中创建对象ss作为调用method方法时的参数
		Student ss = new Student();
		//调用该类中的method方法,不要忘记传参
		sd.method(ss);

                //匿名对象用法
                new StudentDemo().method(new Student());
	}
}

案例2:抽象类作为形参,需要的是该抽象类的子类对象

//抽象类作为形参
//抽象类(抽象类的格式)
abstract class Person{
	public abstract void study();//抽象方法没有具体的方法体
}

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

//定义一个具体的学生类继承自抽象类Person
class Student extends Person{
	//重写抽象类的study方法
	public void study(){
		System.out.println("好好学习,天天向上");
	}
}

//测试类
class PersonTest{
	public static void main(String[] args){
		//使用PersonDemo类中的method方法,在该类中创建对象pd
		PersonDemo pd = new PersonDemo();
		//抽象类Person实例化
		//Person p = new Person();//错误: Person是抽象的; 无法实例化
		//间接实例化
		Person p = new Student();
		pd.method(p);
	}
}

案例3:接口作为形参,需要的是该接口的实现类对象

//接口作为形参
//定义一个兴趣的接口
interface Hobby{
	//接口的成员方法只能是抽象方法
	public abstract void hobby();
}

class HobbyDemo{
	public void method(Hobby h){
		h.hobby();
	}
}

//定义一个具体类来实现接口
class Teacher implements Hobby{
	//方法重写
	public void hobby(){
		System.out.println("卡卡西爱亲热天堂,猫咪老师爱烧酒");
	}
}

//测试类
class HobbyTest{
	public static void main(String[] args){
		//测试HobbyDemo类中的method方法,先创建对象
		HobbyDemo ht = new HobbyDemo();
		Hobby h = new Teacher();
		ht.method(h);
	}
}

返回值类型:

  1. 基本类型
  2. 引用类型(类、抽象类、接口)

案例1:返回值类型为类的时候,返回的其实是该类的对象

class Student {
	public void study() {
		System.out.println("Good Good Study,Day Day Up");
	}
}

class StudentDemo {
	//返回一个Student类型的值,其实是返回Student类的对象
	public Student getStudent() {
		//创建Student类的对象s并返回s
		//Student s = new Student();
		//return s;
		//用匿名对象简化
		return new Student();
	}
}

class StudentTest2 {
	public static void main(String[] args) {
		//调用Student类中的study()方法,不要直接创建Student的对象
		//使用StudentDemo创建对象sd
		StudentDemo sd = new StudentDemo();
		Student s = sd.getStudent(); 
		s.study();
	}
}

案例2:返回值为抽象类的时候,返回的其实是该抽象类的具体类的对象

//定义一个抽象类
abstract class Person {
	public abstract void study();
}

class PersonDemo {
        //返回的是抽象类Person的子类Student的对象
	public Person getPerson() {
		//Person p = new Student();
		//return p;
		//匿名对象简化
		return new Student();
	}
}
//定义抽象类的子类
class Student extends Person {
	//方法重写
	public void study() {
		System.out.println("Good Good Study,Day Day Up");
	}
}

class PersonTest2 {
	public static void main(String[] args) {
		//测试Person类中的study()方法
		PersonDemo pd = new PersonDemo();
		Person p = pd.getPerson(); 
		p.study();
	}
}

案例3:返回值位接口的时候,返回的其实是该接口的实现类的对象

链式编程
        对象.方法1().方法2().......方法n();
        
        这种用法:其实在方法1()调用完毕后,应该返回一个对象;
                  方法2()调用完毕后,应该返回一个对象
                  方法n()调用完毕后,可能是对象,也可以不是对象

匿名对象中,对象是作为参数传递

5. 包和导包

5.1 包的概述

5.1.1 概念

其实就是文件夹

5.1.2 作用

  1. 区分同名的类
  2. 对类进行分类管理
    1. 按照功能分(增、删、查、改)
    2. 按照模块分

5.2 包的定义格式及注意事项

5.2.1 包的定义格式

package 包名;
多级包用.分开即可
举例:
package cn.itcast;

5.2.2 注意事项

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

5.3 带包的类的编译和运行

手动式

  1. javac编译当前类文件。
  2. 手动建立包对应的文件夹。
  3. 把1步骤的class文件放到2步骤的最终文件夹下。
  4. 通过java命令执行    (eg:需要带包名称的执行 java cn.itcast.HelloWorld )

 

自动式

  1. javac编译的时候带上-d即可 javac -d . HelloWorld.java
  2. 通过java命令执行,和手动式步骤4一样

5.4 导包

5.4.1 概述

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

5.4.2 导包格式

import 包名;

这种方式导入是到类的名称。 虽然可以最后写*,但是不建议,建议用谁导谁

思考题:

package,import,class有没有顺序关系?

答:有,package>import>class

  • package只能有一个
  • import能有很多个
  • class能有多个,以后建议只有一个

6. 权限修饰符

6.1 四种权限修饰符

 publicprotected默认private
同一类中访问
同一包中访问子类和其他类 
不同包中访问子类  
不同包中访问其他类   

6.2 类及其组成常用的修饰符

修饰符的分类:

  1. 权限修饰符:public、protected、默认权限修饰符、private
  2. 状态修饰符:static、final
  3. 抽象修饰符:abstract

类 的常用修饰符

  1. 权限修饰符:public(最常用)、默认权限修饰符,protected和private不能修饰类
  2. 状态修饰符:final
  3. 抽象修饰符:abstract

成员变量的常用修饰符:

  1. 权限修饰符:private(最常用),默认的,protected,public
  2. 状态修饰符:static,final

构造方法的常用修饰符:

  1. 权限修饰符:private,默认的,protected,public(最常用)

成员方法的常用修饰符:

  1. 权限修饰符:private,默认的,protected,public(最常用)
  2. 状态修饰符:static,final
  3. 抽象修饰符:abstract

除此以外的组合规则:

  1. 成员变量:public static final
  2. 成员方法:
    1. public static 
    2. public abstract
    3. public final

7. 内部类

7.1 概述

把类定义在其他类的内部,这个类就被称为内部类

7.2 内部类的访问特点

  1. 内部类可以直接访问外部类的成员,包括私有
  2. 外部类要访问内部类的成员,必须创建对象

7.3 内部类的分类

根据内部类在类中定义的位置不同,可以分为两大类:

  1. 成员内部类(内部类在成员位置)
  2. 局部内部类(内部类在成员方法内部,即局部位置)

7.4 成员内部类

案例1:成员内部类访问

要点:

创建对象格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
eg: Outer.Inner oi = new Outer().new Inner();

class Outer {
	private int num = 10;
	class Inner {
		public void show(){
			System.out.println(num);
		}
	}
}

class InnerClassDemo {
	public static void main(String[] args){
		//访问成员内部类Inner的show()方法
                //创建对象格式:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
		Outer.Inner oi = new Outer().new Inner();
		oi.show();
	}
}

成员内部类的常用修饰符

private 为了保证数据的安全性

static 为了让数据访问更方便 (内部类用静态修饰,此时内部类可以看成外部类的成员)

  1. 静态的内部类访问的外部类数据必须是静态修饰的
  2. 内部类被静态修饰后的方法 可以是:
    1. 静态方法 
    2.  非静态方法

7.5 局部内部类

案例:局部内部类访问

  1. 可以直接访问外部类的成员
  2. 可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能
class Outer {
	//定义成员变量
	private int num = 10;
	//定义成员方法
	public void method(){
		//定义局部内部类
		class Inner {
			public void show(){
				System.out.println(num);
			}
		}
		//在局部位置创建内部类对象i调用内部类show方法
		Inner i = new Inner();
		i.show();
	}
}

class InnerClassDemo {
	public static void main(String[] args){
		//创建外部类对象o,通过o访问外部类成员方法method
		Outer o = new Outer();
		o.method();
	}
}

局部内部类访问局部变量 必须用final修饰

原因:

因为局部变量是随着方法的调用二调用,随着方法调用完毕而消失

这时,局部对象并没有立马从堆内存中消失,还要使用那个变量

为了让数据还能继续被使用,就用fianl修饰,这样,在堆内存里面存储的其实是一个常量值

7.6 匿名内部类

匿名内部类其实就是内部类的简化写法

前提:存在一个类或者接口

  • 这里的类可以是具体类也可以是抽象类
格式:
new 类名或者接口名() {
    重写方法;
}

本质: 是一个继承了该类或者实现了该接口的子类匿名对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值