第八章 总结

文章目录

 

类包

 

在Java中,我们可以使用class关键字来进行定义一个类,在程序被编译后就会产生一个.class文件。类的定义是规定类名不能重复的,如果程序内只定义了少量的类,那自然不用担心这个问题。
但是,随着类的数量增多,那么难免会出现这个问题,如果根据需求需要定义两个名字相同但是程序逻辑不同的类时,那么该如何解决呢,最好的方法就是将这个两个类放置在不同的包下面。

 

类的定义规定,在同一个类包下面不允许出来同名的类,但是在不同类包下面就允许出现这种情况,相当于将两个同名的类放入了不同的盒子内,避免出现这个问题。

包和类的关系
8c2d49910fd54ea18afbaadf456777db.png
 

类路径

如果一个程序内存在多个同名不同包的max类,那么该如何使用指定包的类呢?
在使用该类时使用该类的类路径,也成为绝对路径

 

java.util.Date date=new java.util.Date(); // 选择Java.util包下的Date类 java.sql.Date date2=new java.sql.Date(100) // 选择Java.sql包下的Date类

  • 1
  • 2

 

指定包名(package)

在进行创建包的时候需要注意的是,Java包的命名规则建议使用全小写字母进行命名。
需要了解的是如果一个类没有被定义在一个指定的包内,那么该类就被归纳到默认包(default package)中。

 

在某个包下面创建一个类的话,需要在这个类的开头加上表达式 package 包名,该表达式需要放置在程序的第一行,使用package关键字指定包名之后,包名也会成为类名的一部分,在不同包下使用该类的话,需要使用 import 包名.类名 的格式。

 

package test; //指定包名,表示该类在本包内 public class dome{ }

  • 1
  • 2
  • 3

 

导包

 

在Java中,如果需要使用到其它包内的类的话,除了使用该类的绝对路径之外,我们还可以使用Java中 import 关键字来指定。例如,如果在其它包内也定义了一个Math,那么假如我们只想使用该Math类的话,那么我们可以使用import关键字进行导包。

例如:

 

package test; import Number_5.Math; //导包,导入其它包内的Math类 public class Demo_4 { public static void main(String[] args) { int max = Math.max(4, 6); // 进行导包后,再使用时,直接使用包名.类名的方法进行使用 System.out.println(max); } }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

在进行导包后,我们在使用该包下的Math类后,可以看到,java.lang包下有一个Java给定的Math类,还有一个我们刚刚进行导的包下的Math类。

0ae46e0f39a24cba908e8f2a0b4754ff.png

 

需要注意的是,刚刚我们已经导入了Number_5包下的Math类,如果需要使用java.lang包下的Math类的话,需要使用java.lang.Math类的完整路径的方式使用该类。因为如果在之前导入了Number_5包下的Math类的话,程序中如果使用Math类中的方法,编译器只会去Number_5.Math类内进行寻找该方法,如果没有找到则报错。

ef8093af83a54d7bb1d3d36a4e0ff2a4.png
 

如果需要使用java.lang包下的Math类的话,需要使用全名格式,指定编译器去那个包下寻找min方法。
d55eaf2a672542e6894b1cd89344b581.png
 

需要注意的是,如果使用import导入某个包下的所有类时,这些类并不包括该包下的子包的类。如果需要使用子包中的类时,需要对子包进行单独引用。

 

import 包名.子包名.*; //导入所有类 import 包名.子包名.类名; //导入指定类

  • 1
  • 2


 

导入静态方法或静态成员

使用import关键字还可以对静态方法与静态变量进行导包。

 

import java.lang.max; import java.lang.System.out; public class Demo{ public static void main(String[] args){ out.println("较大值为:"+(max(1,4))); // 导入后可直接使用 } }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8


 

内部类

 

内部类顾名思义,就定义在一个类内部的类。

db9c8776b0904252b8e62f219c7cddf9.png



 

成员内部类

定义在一个类成员位置的内部类,称为成员内部类,在成员内部类中可以使用外部类的的任意成员变量与成员方法,即使该外部类成员变量被private所修饰。

 

package test; public class Demo_4 { private int num; static int i=0; // 内部类 class test{ public void show(){ // 内部类调用外部类的成员变量 System.out.println(num); System.out.println(i); } } }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

因为private等权限修饰符是针对外界的调用而进行权限判断的,但是成员内部类定义在该类的内部,那么相对于该类的一部分,就像该类的方法也是可以调用被private修饰的成员变量一般,成员内部类属于外部类的成员之一。

内部类是依赖于外部类的存在而存在。除非程序中已经有了一个外部类的对象,否则内部类一般不会单独存在。

 

内部类也可以被权限修饰符进行修饰,如果内部类被private修饰,那么外界无法创建内部类的对象,只能在外部类中创建内部类的对象。

 

该如何获取内部类的对象呢?

两种方法:

  1. 对外部类编写get方法,对外提供内部类的对象
  2. 如果内部类没有被private修饰,那么可以在外界创建一个内部类的对象;

 

方法二:直接创建内部类对象

成员内部类创建对象格式:

外部类.内部类 类名 = 外部类对象.new 内部类构造方法();

 

public class Demo_4{ public static void main(String[] args) { W.N j=new W().new N(); // 链式法创建内部类对象 } } // 外部类 class W { // 内部类 class N { } }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

 

方法一:通过get方法对外提供成员内部类对象
这个方法多用于成员内部类被private修饰时,才使用这个方法。

但是如果成员内部类被private修饰了,那么外界也无法使用成员内部类的变量来接收这个返回值,只能使用多态的方式,让成员内部类的父类进行接收,如果该成员内部类没有继承其它类,那么只能使用Object来接收这个返回值

 

public class Demo_4{ public static void main(String[] args) { Object a = new W().getN(); } } class W { private class N { } public N getN(){ return new N(); } }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

 

外部类与内部类之间也可使用this关键字,如果在内部类中需要使用到外部类的成员变量,那么可以使用外部类.this.变量名的方式使用。

例如:

 

public class Demo_4{ public static void main(String[] args) { W.N a=new W().new N(); a.show(); } } class W { private int i=10; class N { private int i=20; public void show(){ int i=30; System.out.println(i); // 方法内的i System.out.println(this.i); // 内部类的i System.out.println(W.this.i); // 外部类的i } } }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

fdaba90f8c5646f6b707196a0d687dd9.png

 

匿名内部类

匿名内部类本质是一个隐藏了名字的内部类。匿名类是只有在创建时才会编写类体的一种写法。

语法格式:

 

new 继承/实现(){ //重写的方法 };

  • 1
  • 2
  • 3

匿名内部类在一对大括号 { } 的范围内是一个类,整体却是一个new出来的对象。

 

例如:

 

public class Demo_4{ public static void main(String[] args) { // 匿名内部类 new Swit(){ @Override public void swit(){ System.out.println("重写了swit方法"); } }; } } interface Swit{ public void swit(); }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

上述匿名内部类处的语法解读。
1fa2715c3506429f9b52284caf7bb4b3.png

整体来说就是,使用空参构造创建一个实现了Swit接口的匿名内部类的对象,就是说,创建匿名内部类的地方是创建了一个对象。

匿名内部类编译后会产生一个以 “外部类名$序号“ 为名称的 .class文件,序号以1-n排列,分别代表1-n个匿名内部类。那么我们可以找到这个.class文件,并对其进行反编译来查看我的结论是否正确。

 

匿名内部类产生的.class文件
6df7d9d8b1374033a77eb71ac72f61cd.png
javap 命令,可以对.class文件进行反编译,将字节码文件进行反编译,会打印出该字节码文件包含的信息

 

反编译的结果:被圈起来的是虚拟机自行添加的空参构造与重写的接口方法。
8325ad160e2f493489d27bb611f1d930.png

上述反编译的结果可以说明,使用匿名内部类的格式创建的是一个匿名内部类的对象,而大括号内{}的才是匿名内部类的类体。

 

  1. 匿名内部类的对象如果没有赋值给任何引用变量的话,该对象会在使用后被Java虚拟机自动销毁。
  2. 匿名类不能写构造方法。
  3. 匿名类不能定义静态的成员。

那么匿名内部类对象可以赋值给那些引用变量呢?可以被赋值给被继承的接口或者父类对象。形成多态。

父类对象调用子类方法

 

public class Demo_4{ public static void main(String[] args) { Swit s=new Swit(){ public void swit(){ System.out.println("重写了swit方法"); } }; s.swit(); // 父类对象调用子类重写的方法 } } interface Swit{ public void swit(); }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

 

运行过程

c10881b6c8c94495828c2d3dac337b3c.png

匿名内部类的那个整体是一个对象,只有大括号内的才是那个具体的匿名内部类。


 

End

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值