Java面向对象

面向对象思想引入

前面我们讲过数组,当有多个数组都需要遍历时,我们可以将遍历的代码封装到方法中,需要遍历时,就调用相应的方法即可,提高代码的复用性。在对数组遍历的基础上继续增加需求,比如获取最值,数值逆序等,同样需要将这些功能封装到相应的方法中。这样继续封装会发现方法越来越多,于是就想能不能将这些方法继续进行封装呢?通过前面的讲解我们知道类是可以存放方法的,所以,我们就考虑使用类封装来这多个方法,将来再做数组的操作时,不用去找具体的方法,先找到这个类,然后使用这个类中的方法。这就是面向对象思想的编程方式。

面向过程思想概述

  • 我们来回想一下,我们完成一个需求的步骤:首先是搞清楚我们要做什么,然后在分析怎么做,最后我们再代码体现。一步一步去实现,而具体的每一步都需要我们去实现和操作。这些步骤相互调用和协作,完成我们的需求。
  • 在上面的每一个具体步骤中我们都是参与者,并且需要面对具体的每一个步骤和过程,这就是面向过程最直接的体现。
  • 那么什么是面向过程开发呢?
    面向过程开发,其实就是面向着具体的每一个步骤和过程,把每一个步骤和过程完成,然后由这些功能方法相互调用,完成需求。
  • 面向过程的代表语言:C语言
  • 当需求单一,或者简单时,我们一步一步去操作没问题,并且效率也挺高。可随着需求的更改,功能的增多,发现需要面对每一个步骤很麻烦了,这时就开始思索,能不能把这些步骤和功能在进行封装,封装时根据不同的功能,进行不同的封装,功能类似的封装在一起。这样结构就清晰了很多。用的时候,找到对应的类就可以了。这就是面向对象的思想。接下来我们看看面向对象到底是什么?
  • 面向对象思想概述

    面向对象是基于面向过程的编程思想

  • 面向对象思想特点

    是一种更符合我们思想习惯的思想

    可以将复杂的事情简单化

    将我们从执行者变成了指挥者
    角色发生了转换

面向对象开发,设计,特征

  • 面向对象开发

    就是不断的创建对象,使用对象,指挥对象做事情。

  • 面向对象设计

    其实就是在管理和维护对象之间的关系。

  • 面向对象特征

    封装(encapsulation)
    继承(inheritance)
    多态(polymorphism)

类与对象关系

  • 我们学习编程语言,就是为了模拟现实世界的事物,实现信息化。比如:去超市买东西的计费系统,去银行办业务的系统。

  • 我们如何表示一个现实世界事物呢:

    属性 就是该事物的描述信息
    行为 就是该事物能够做什么
    举例:学生事物

  • 我们学习的Java语言最基本单位是类,所以,我们就应该把事物用一个类来体现。

  • 类:是一组相关的属性和行为的集合

  • 对象:是该类事物的具体体现

  • 举例:

    类 学生
    对象 班长就是一个对象

类:可以理解为构造对象的一个蓝图或者模版,是抽象的概念
对象:是以类为模型创建的具体实例,是对类的一种具体化。

类与对象(图例)

类与对象的关系如图
这里写图片描述
1:图纸就是类
2:每一个汽车就是一个个的对象

类的定义

  • 现实世界的事物

    属性 人的身高,体重等
    行为 人可以学习,吃饭等

  • Java中用class描述事物也是如此 成员变量 就是事物的属性

    成员方法 就是事物的行为
    定义类其实就是定义类的成员(成员变量和成员方法)

成员变量和局部变量的区别

  • 在类中的位置不同

    成员变量 类中方法外
    局部变量 方法内或者方法声明上

  • 在内存中的位置不同

    成员变量 堆内存
    局部变量 栈内存

  • 生命周期不同

    成员变量 随着对象的存在而存在,随着对象的消失而消失
    局部变量 随着方法的调用而存在,随着方法的调用完毕而消失

  • 初始化值不同

    成员变量 有默认的初始化值
    局部变量 没有默认的初始化值,必须先定义,赋值,才能使用。

形式参数问题

  • 基本类型作为形式参数

  • 引用类型作为形式参数

匿名对象

  • 匿名对象:就是没有名字的对象。

    是对象的一种简化表示形式

  • 匿名对象的两种使用情况

    对象调用方法仅仅一次的时候
    作为实际参数传递

封装概述

  • 封装概述

    是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。

  • 好处:

    隐藏实现细节,提供公共的访问方式
    提高了代码的复用性
    提高安全性。

  • 封装原则:

    将不需要对外提供的内容都隐藏起来。
    把属性隐藏,提供公共方法对其访问。

private关键字

  • private关键字:

    是一个权限修饰符。
    可以修饰成员(成员变量和成员方法)
    被private修饰的成员只在本类中才能访问。

  • private最常见的应用:

    把成员变量用private修饰
    提供对应的getXxx()/setXxx()方法

this关键字

  • this:代表所在类的对象引用
  • 记住:

    方法被哪个对象调用,this就代表那个对象

  • 什么时候使用this呢?

    局部变量隐藏成员变量
    其他用法后面和super一起讲解

构造方法

  • 构造方法作用概述

    给对象的数据进行初始化

  • 构造方法格式

    方法名与类名相同
    没有返回值类型,连void都没有
    没有具体的返回值

  • 构造方法注意事项

    如果你不提供构造方法,系统会给出默认构造方法
    如果你提供了构造方法,系统将不再提供
    构造方法也是可以重载的

类的成员方法

  • 成员方法其实就是我们前面讲过的方法

  • 方法具体划分:

    • 根据返回值

      有明确返回值方法
      返回void类型的方法

    • 根据形式参数

      无参方法
      带参方法

一个基本类的标准代码写法

  • 成员变量

  • 构造方法

    无参构造方法
    带参构造方法

  • 成员方法

    getXxx()
    setXxx()

  • 给成员变量赋值的方式

    无参构造方法+setXxx()
    带参构造方法

类的初始化过程

Student s = new Student();在内存中做了哪些事情?
1.加载Student.class文件进内存
2.在栈内存为s开辟空间
3.在堆内存为学生对象开辟空间
4.对学生对象的成员变量进行默认初始化
5.对学生对象的成员变量进行显示初始化
6.通过构造方法对学生对象的成员变量赋值
7.学生对象初始化完毕,把对象地址赋值给s变量

static关键字

  • 可以修饰成员变量和成员方法
  • static关键字特点

    随着类的加载而加载
    优先于对象存在
    被类的所有对象共享(这也是我们判断是否使用静态关键字的条件)
    可以通过类名调用

  • static关键字注意事项

    在静态方法中是没有this关键字的
    静态方法只能访问静态的成员变量和静态的成员方法

静态变量和成员变量的区别

  • 所属不同

    静态变量属于类,所以也称为为类变量
    成员变量属于对象,所以也称为实例变量(对象变量)

  • 内存中位置不同

    静态变量存储于方法区的静态区
    成员变量存储于堆内存

  • 内存出现时间不同

    静态变量随着类的加载而加载,随着类的消失而消失
    成员变量随着对象的创建而存在,随着对象的消失而消失

  • 调用不同

    静态变量可以通过类名调用,也可以通过对象调用
    成员变量只能通过对象名调用

main方法是静态的

public static void main(String[] args) {}

public 被jvm调用,访问权限足够大。
static 被jvm调用,不用创建对象,直接类名访问
void被jvm调用,不需要给jvm返回值
main 一个通用的名称,虽然不是关键字,但是被jvm识别
String[] args 以前用于接收键盘录入的

代码块

  • 在Java中,使用{}括起来的代码被称为代码块,根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代码块。
  • 局部代码块

    在方法中出现;限定变量生命周期,及早释放,提高内存利用率

  • 构造代码块

    在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行
    静态代码块 在类中方法外出现,加了static修饰
    在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且值执行一次。

继承概述

  • 继承概述

    多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
    通过extends关键字可以实现类与类的继承
    class 子类名 extends 父类名 {}
    单独的这个类称为父类,基类或者超类;这多个类可以称为子类或者派生类。
    有了继承以后,我们定义一个类的时候,可以在一个已经存在的类的基础上,还可以定义自己的新成员。

继承的好处

  • 提高了代码的复用性

    多个类相同的成员可以放到同一个类中

  • 提高了代码的维护性

    如果功能的代码需要修改,修改一处即可

  • 让类与类之间产生了关系,是多态的前提

    其实这也是继承的一个弊端:类的耦合性很强

Java只支持单继承,不支持多继承。
一个类只能有一个父类,不可以有多个父类。

class SubDemo extends Demo{} //ok
class SubDemo extends Demo1,Demo2...//error

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

class A{}
class B extends A{}
class C extends B{}

Java中继承的注意事项

  • 子类只能继承父类所有非私有的成员(成员方法和成员变量)

    其实这也体现了继承的另一个弊端:打破了封装性

  • 子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。

    不要为了部分功能而去继承

  • 我们到底在什么时候使用继承呢?

    继承中类之间体现的是:”is a”的关系。

继承中成员变量的关系

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

结论:

  • 在子类方法中访问一个变量

    首先在子类局部范围找
    然后在子类成员范围找
    最后在父类成员范围找(肯定不能访问到父类局部范围)
    如果还是没有就报错。(不考虑父亲的父亲…)

super关键字

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

    访问成员变量
    this.成员变量 super.成员变量
    访问构造方法(子父类的构造方法问题讲)
    this(…) super(…)
    访问成员方法(子父类的成员方法问题讲)
    this.成员方法() super.成员方法()

1:看程序写结果

    class Test
    {
        private static int x =  10;

        public void show(int x)  
        {
            x++;
            System.out.println(x);
        } 

        public static void main(String[] args)
        {
            int x = 20; 
            Test t = new Test();
            t.show(x);
        }
    } 

结果:21

继承中构造方法的关系

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

  • 为什么呢?

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

  • 如何父类中没有构造方法,该怎么办呢?

    子类通过super去显示调用父类其他的带参的构造方法
    子类通过this去调用本类的其他构造方法
    本类其他构造也必须首先访问了父类构造

  • 一定要注意:

    super(…)或者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();
        }
    }

这里写图片描述
2:面试题

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");
        }
    }

    Zi z = new Zi(); 请执行结果。

    A:静态随着类的加载而加载。
    B:静态代码块 -- 构造代码块 -- 构造方法的执行流程
        静态代码块 -- 构造代码块 -- 构造方法
    C:只要有子父关系,肯定先初始化父亲的数据,然后初始化子类的数据。

    结果:
        静态代码块Fu
        静态代码块Zi
        构造代码块Fu
        构造方法Fu
        构造代码块Zi
        构造方法Zi

3:面试题

    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(); 
        }
    }

结果:
这里写图片描述

【铺垫的小知识】:

  • 第一个:成员变量有基本类型和引用类型的。

        class Demo {
            //基本类型
            int x = 10;
            //引用类型
            Student s = new Student();
        }
  • 第二个:类的初始化过程

    加载class文件
    堆中开辟空间
    变量的默认初始化
    变量的显示初始化
    构造代码块初始化
    构造方法初始化

  • 第三个:遇到extends,就要知道,先初始化父类数据,然后初始化子类数据。

    分层初始化。
    super在这里仅仅表示要先初始化父类数据。

继承中成员方法的关系

1:在父类中定义一个成员方法
2:在子类中定义一个成员方法和父类中成员方法名称不同,然后在测试类中通过子类对象去访问方法,发现方法名不同,访问非常简单
3:在子类中再定义一个成员方法,和父类中的成员方法名称一致,然后继续访问。发现访问的是子类的成员方法。
4:如果我要访问父类的成员方法该怎么办呢?回想刚才提过的super关键字

结论:

  • 通过子类对象去访问一个方法

    首先在子类中找
    然后在父类中找
    如果还是没有就报错。(不考虑父亲的父亲…)

  • 方法重写概述

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

  • 使用特点:

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

  • 方法重写的应用:

    当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。

  • 方法重写的注意事项

    父类中私有方法不能被重写
    子类重写父类方法时,访问权限不能更低
    父类静态方法,子类也必须通过静态方法进行重写。

final关键字

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

    修饰类,类不能被继承
    修饰变量,变量就变成了常量,只能被赋值一次
    修饰方法,方法不能被重写

  • final关键字面试题

    • final修饰局部变量

      在方法内部,该变量不可以被改变
      在方法声明上,分别演示基本类型和引用类型作为参数的情况
      1.基本类型,是值不能被改变
      2.引用类型,是地址值不能被改变

    • final修饰变量的初始化时机

      在对象构造完毕前即可

多态概述

  • 多态概述

    某一个事物,在不同时刻表现出来的不同状态。

  • 举例:

    猫可以是猫的类型。猫 m = new 猫();
    同时猫也是动物的一种,也可以把猫称为动物。
    动物 d = new 猫();
    在举一个例子:水在不同时刻的状态

  • 多态前提和体现

    有继承关系
    有方法重写
    有父类引用指向子类对象

多态案例及成员访问特点

  • 成员访问特点

    成员变量
    编译看左边,运行看左边

  • 成员方法

    编译看左边,运行看右边

  • 静态方法

    编译看左边,运行看左边
    所以前面我说静态方法不能算方法的重写

面试题:
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();
    }
}

这里写图片描述

2.看程序写结果

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.show();
    }
}

这里写图片描述

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

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 Test 
{
    public static void main(String[] args) 
    {
        A a = new B();
        a.show();

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

这里写图片描述

多态的好处和弊端

  • 多态的好处

    提高了程序的维护性(由继承保证)
    提高了程序的扩展性(由多态保证)

  • 多态的弊端

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

多态中的转型问题

  • 向上转型

    从子到父
    父类引用指向子类对象

  • 向下转型

    从父到子
    父类引用转为子类对象

抽象类概述

  • 抽象类概述
    我说动物,你知道我说的是什么动物吗?只有看到了具体的动物,你才知道,这是什么动物。 所以说,动物本身并不是一个具体的事物,而是一个抽象的事物。只有真正的猫,狗才是具体的动物。同理,我们也可以推想,不同的动物吃的东西应该是不一样的,所以,我们不应该在动物类中给出具体体现,而是应该给出一个声明即可。

    在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类。

抽象类特点

  • 抽象类和抽象方法必须用abstract关键字修饰
  • 格式

    abstract class 类名 {}
    public abstract void eat();

  • 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类

  • 抽象类不能实例化

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

  • 抽象类的子类

    要么是抽象类
    要么重写抽象类中的所有抽象方法

抽象类的成员特点

  • 成员变量

    可以是变量
    也可以是常量

  • 构造方法

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

  • 成员方法

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

  • abstract不能和哪些关键字共存

    private 冲突
    final 冲突
    static 无意义

接口概述

我们想想狗一般就是看门,猫一般就是作为宠物了,对不。但是,现在有很多的驯养员或者是驯兽师,可以训练出:猫钻火圈,狗跳高,狗做计算等。而这些额外的动作,并不是所有猫或者狗一开始就具备的,这应该属于经过特殊的培训训练出来的,对不。所以,这些额外的动作定义到动物类中就不合适,也不适合直接定义到猫或者狗中,因为只有部分猫狗具备这些功能。所以,为了体现事物功能的扩展性,Java中就提供了接口来定义这些额外功能,并不给出具体实现,将来哪些猫狗需要被培训,只需要这部分猫狗把这些额外功能实现即可。

接口特点

  • 接口用关键字interface表示

    格式:interface 接口名 {}

  • 类实现接口用implements表示

    格式:class 类名 implements 接口名 {}

  • 接口不能实例化

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

  • 接口的子类

    要么是抽象类
    要么重写接口中的所有抽象方法

接口成员特点

  • 成员变量

    只能是常量
    默认修饰符 public static final

  • 构造方法

    没有,因为接口主要是扩展功能的,而没有具体存在

  • 成员方法

    只能是抽象方法
    默认修饰符 public abstract

类与类,类与接口以及接口与接口的关系

  • 类与类

    继承关系,只能单继承,但是可以多层继承

  • 类与接口

    实现关系,可以单实现,也可以多实现。还可以在继承一个类的同时实现多个接口

  • 接口与接口

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

抽象类和接口的区别

  • 成员区别

    抽象类 变量,常量;有抽象方法;抽象方法,非抽象方法
    接口 常量;抽象方法

  • 关系区别

    类与类 继承,单继承
    类与接口 实现,单实现,多实现
    接口与接口 继承,单继承,多继承

  • 设计理念区别

    抽象类 被继承体现的是:”is a”的关系。共性功能
    接口 被实现体现的是:”like a”的关系。扩展功能

形式参数和返回值

  • 形式参数

    基本类型
    引用类型

  • 返回值类型

    基本类型
    引用类型

  • 链式编程

1:形式参数的问题在前面匿名对象的时候已经讲解过了。
但是,今天又多了抽象类和接口类型作为形式参数。

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

具体类作为形式参数:

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

class StudentDemo {
    //如果参数是一个类名,那么实际需要的是一个具体的对象
    public void method(Student s) {
        s.show();
    }
} 

class StudentTest {
    public static void main(String[] args) {
        //如何调用StudentDemo中的method方法呢?
        StudentDemo sd = new StudentDemo();
        Student s = new Student();
        sd.method(s);
    }
}

抽象类作为形式参数:

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

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

//自己定义类继承自Person类

class PersonTest {
    public static void main(String[] args) {
        //如何调用PersonDemo中的method方法呢?
        PersonDemo pd = new PersonDemo ();
        Person p = new Student();
        pd.method(p);
    }

}

接口作为形式参数,类似抽象类作为形式参数。

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

具体类作为返回值类型:

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

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

class StudentTest {
    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 PersonDemo {
    public Person getPerson() {
        Person p = new ???();
        return p;

        return new ???();
    }
}

//自己定义类继承自Person类,否则PersonDemo代码无法完成?

class PersonTest {
    public static void main(String[] args) {
        //如何调用PersonDemo中的method方法呢?
        PersonDemo pd = new PersonDemo ();
        Person p = pd.getPerson();
        p.show(); //其实调用的是Student的
    }

}

接口作为返回值类型,类似抽象类作为返回值类型

3:链式编程的案例演示

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

  • 包的概述

    其实就是文件夹

  • 作用:对类进行分类管理

  • 包的划分:

    举例:
    学生的增加,删除,修改,查询
    老师的增加,删除,修改,查询
    以及以后可能出现的其他的类的增加,删除,修改,查询
    基本的划分:按照模块和功能分。
    高级的划分:就业班做项目的时候你就能看到了。

包的定义及注意事项

  • 定义包的格式

    package 包名;
    多级包用.分开即可

  • 注意事项:

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

带包的类的编译和运行

  • 手动式

    a:javac编译当前类文件。
    b:手动建立包对应的文件夹。
    c:把a步骤的class文件放到b步骤的最终文件夹下。
    d:通过java命令执行。注意了:需要带包名称的执行
    java cn.itcast.HelloWorld

  • 自动式

    a:javac编译的时候带上-d即可
    javac -d . HelloWorld.java
    b:通过java命令执行。和手动式一样

导包

  • 导包概述

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

  • 导包格式

    import 包名;

  • 注意:

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

权限修饰符

这里写图片描述

类及其组成可以用的修饰符类:

  • 类:
    默认,public,final,abstract
    我们自己定义:public居多
  • 成员变量:

    四种权限修饰符均可,final,static
    我们自己定义:private居多

  • 构造方法:

    四种权限修饰符均可,其他不可
    我们自己定义:public 居多

  • 成员方法:

    四种权限修饰符均可,fianl,static,abstract
    我们自己定义:public居多

内部类概述

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

    举例:在类A中定义了一个类B,类B就是内部类。

  • 内部类的访问特点:

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

内部类位置

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

    成员位置(成员内部类)
    局部位置(局部内部类)

  • 成员内部类

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

成员内部类

  • 一般内部类就是不让外界直接访问的。

    举例讲解这个问题:Body和Heart,电脑和CPU。

  • 成员内部的常见修饰符

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

成员内部类面试题

补齐程序(注意:内部类和外部类没有继承关系)

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

在控制分别输出:30,20,10

答案:

class Outer {
    public int num = 10;

    class Inner {
        public int num = 20;

        public void show() {
            int num = 30;
            System.out.println(num);
            System.out.println(this.num);
            System.out.println(Outer.this.num);
        }
    }
}

class OuterDemo {
    public static void main(String[] args) {
        Outer.Inner oi = new Outer().new Inner();
        oi.show();
    } 
}

局部内部类

  • 可以直接访问外部类的成员
  • 可以创建内部类对象,通过对象调用内部类方法,来使用局部内部类功能
  • 局部内部类访问局部变量的注意事项:

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

class Outer {
    public void method() {
        final int n = 100;
        class Inner {
            public void show() {
                System.out.println(n);
            }
        }

        Inner i = new Inner();
        i.show();
    }
}

class OuterDemo {
    public static void main(String[] args) {
        Outer o = new Outer();
        o.method();
    } 
}

这里写图片描述

匿名内部类

  • 就是内部类的简化写法。
  • 前提:存在一个类或者接口

    这里的类可以是具体类也可以是抽象类。

  • 格式:

    new 类名或者接口名() {重写方法;}

  • 本质:

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

匿名内部类在开发中的使用

首先回顾我们曾经讲过的方法的形式参数是引用类型的情况,重点是接口的情况,我们知道这里需要一个子类对象。而匿名内部类就是一个子类匿名对象,所以,可以使用匿名内部类改进以前的做法。

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

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

class PersonTest {
    public static void main(String[] args) {
        //如何调用PersonDemo中的method方法呢?
        PersonDemo pd = new PersonDemo ();
        pd.method(new Person() {
            public void show() {
                System.out.println(“show”);
            }
        });
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值