目录
一、Java类包
类包(包):
1. 每个类都隶属于一个类包;
2. 一个包中的类的类名不能重复,不同包中的类名不相互影响,但这样指定时就必须给出完整路径;
3. 类包(包)能有效避免同名类冲突的情况;
4. 同一个包中的类相互访问时,可以不指定包名;
5. 同一个包中的类不必放在同一个位置。如com.lzw.class1和com.lzw.class2可以一个放在C盘一个放在D盘,只要将CLASSPATH分别指向这两个位置即可。
1、包的创建
1)包的命名:命名规则:全部使用小写字母
Java中包名设计应与文件系统结构相对应。如一个包名为com.lzw,那么该包的类位于com文件夹下的lzw子文件夹下。
2)包的创建:
1---在Eclipse中创建包----右键src,new,package----按上述格式命名。
2---在类中定义包名----必须是文件中第一行非注释代码
package 包名;
当使用package关键字为类指定包名之后,包名将会成为类名中的一部分,则这个类必须指定全名。
package com.lzw; //指定包名
public class Math{
public static void main(String[] args){
System.out.prinln("不是java.lang.Math类,而是com.lzw.Math类");
}
}
2、导入包
1)使用import关键字导入包
import com.lzw.Math;
import com.lzw2.*;
a、如果类定义中已经导入com.lzw.Math类,在类体重在使用其他包中的Math类时则必须指定完整的带有包格式的类名。
b、在程序中添加import关键字时,就开始在CLASSPATH指定的目录中进行查找,查找子目录中com.lzw,然后从这个目录下编译完成的文件中查找是否有名称符合者,最后寻找到Math.class文件。
c、当使用import制定了一个包中的所有类时,并不会制定这个包的子包中的类。如果要用到这个包中的子类,需要再次对子包作单独引用。
d、
2)使用import导入静态成员变量
import static 静态成员;
可以在程序中直接引用这些导入的静态成员:
package com.lzw;
import static java.lang.Math.max; //导入静态成员方法
import static java.lang.System.out; //导入静态成员变量
public class ImportTest{
public static void main(String[] args){
out.prinln(max(1,4)); //在主方法中可以直接使用这些静态成员
}
}
二、final变量
private final double PI = 3.14; | 声明一个final常量。 不可以再改变该常量的值。 |
必须在声明时对该常量进行赋值。 定义为final的常量需要使用大写字母命名, 且中间用下划线连接。 |
private static final int VALUE = 10; | 声明一个final、static常量 | |
private final A a = new A(); | 声明一个final引用 | 不能将定义为final的引用指向其他引用; 可以对指定为final的引用中的成员变量赋值 |
private final int[] a = {1,2,3}; | 声明一个定义为final的数组 | 不能对定义为final的数组赋值 |
package com.lzw;
import java.util.Random;
import static java.lang.System.out;
public class FinalStaticData {
public static Random rand = new Random(); //实例化一个Random类对象
private final int a1 = rand.nextInt(10); //定义为final的成员变量a1
//随机产生0~10之间的随机数,赋予定义为 final 的 a1
//a1是”rand.nextInt(10)“的引用
//在再次调用时,这个引用的对象没有变
//但是这个引用本身的值会变,之后输出两次结果会变
private static final int a2 = rand.nextInt(10); //定义为static final的成员变量a2
//a2是”rand.nextInt(10)“的引用
//在再次调用时,这个引用的对象没有变
//且因为static final,这个引用本身的值也不能变
//之后两次输出结果是一样的
public static void main(String[] args) {
FinalStaticData fsdata = new FinalStaticData(); //实例化一个对象fsdata
out.println("用实例化对象fsdata调用a1的值:" + fsdata.a1);
out.println("用实例化对象fsdata调用a2的值:" + fsdata.a2);
FinalStaticData fsdata2 = new FinalStaticData(); //再实例化一个对象fsdata2
out.println("用另一个实例化对象fsdata2调用a1的值:" + fsdata2.a1);
out.println("用另一个实例化对象fsdata2调用a2的值:" + fsdata2.a2);
}
}
结果为:
Java中定义全局变量,通常使用public static final修饰,这样的变量只能在定义时被赋值。
三、final方法
定义为final的方法不能被重写。定义为final的方法的执行效率要高于非final方法。
如果父类的某一个方法被设置为private修饰符,子类无法访问爱方法,自然无法覆盖该方法。所以一个定义为private的方法隐式被指定为final类型。
class Parents{
private final void doit() {
System.out.println("Parents.doit()");
}
final void doit2() {
System.out.println("Parents.doit2()");
}
public void doit3() {
System.out.println("Parents.doit3()");
}
}
class Sub extends Parents{
public final void doit() {
System.out.println("Sub.doit()");
}
/*final void doit2() {
System.out.println("Sub.doit2()");
}*/
public void doit3() {
System.out.println("Sub.doit3()");
}
}
public class FinalMethod {
public static void main(String[] args) {
Sub s = new Sub();
s.doit();
Parents p = s;
// p.doit();
p.doit2();
p.doit3();
}
}
看起来好像doit()方法被重写了,实际上是在Sub中生成的一个新方法,而不是父类Parents中方法的重写。
而且Sub类对象s向上转型为p后,“p.doit();”语句报错:“The method doit() from the type Parents is not visible”
四、final类
1. 定义为final的类不能被继承;
final class 类名{}
2. final类的中的所有方法都被隐式设置为final形式,但是final类中的成员变量可以被定义为final或者非final形式。
final class FinalClass {
int a = 3; //final类中的非final成员变量
void doit() {
}
public static void main(String[] args) {
FinalClass f = new FinalClass();
f.a++; //final类中的非final成员变量更改
System.out.println(f.a); //结果为4
}
}
五、内部类
如果在类中再定义一个类,则将在类中再定义的那个类称为内部类。
在一个类中使用内部类,可以在内部类中直接存取其所在类的私有成员变量
1. 成员内部类
public class OuterClass { //外部类
private class InnerClass{ //内部类
//…
}
}
在内部类中可以随便使用外部类的成员方法以及成员变量,就算这些类成员被修饰为private。
外部类不可以直接访问内部类成员变量。只能通过“”“在外部类中初始化的内部类对象+“.”+内部类成员变量”“”方式访问。
如果从外部类中初始化一个内部类对象,那么该内部类对象就会绑定在外部类对象上。内部类的对象实例化操作必须在外部类或外部类的非静态方法中实现。
在主方法中实例化内部类对象,必须在new操作符之前提供一个外部类的引用(外部类的一个对象的名字),or调用外部类中返回类型为内部类对象的外部类方法:
(不能再new操作符之前使用外部类名称实例化内部类对象,而是应该使用外部类的对象来创建其内部类对象)
public static void main(String[] args){
OuterClass out = new OuterClass();
OUterClass.InnerClass in1 = out.doit(); //doit()为返回类型为InnerClass的外部类方法
OuterClass.InnerClass in2 = out.new InnerClass();
}
(具体代码:)
public class OuterClass1 {
class InnerClass{
InnerClass(){} //内部类构造方法
int y = 0; //定义内部类成员变量
private String getY() { //内部类成员方法
return String.valueOf(y);
}
}
private InnerClass doit() { //外部类方法,返回值为内部类引用
InnerClass inner = new InnerClass();
//y = 4; //外部类不能直接访问内部类成员变量
inner.y = 4;
return inner; //返回内部类引用
}
public static void main(String[] args) {
OuterClass1 out = new OuterClass1();
//内部类对象实例化只能在外部类或外部类非静态方法中实现
OuterClass1.InnerClass in = out.new InnerClass();
OuterClass1.InnerClass in2 = out.doit();
System.out.println(in.getY()); //0
System.out.println(in2.getY()); //4
}
}
如果将一个权限修饰符为private的内部类向上转型为其父类对象,或者直接向上转型为一个接口,在程序中就可以完全隐藏内部类的具体实现过程。
可以在外部提供一个接口,在接口中是声明一个方法。如果在实现该接口的内部类中实现该接口的方法,就可以在定义多个内部类以不同的方式实现接口中的同一个方法。
interface OutInterface{
public void f();
}
class OuterClass2{
public OutInterface doit() { //外部类的doit()方法,返回值类型为OutInterface接口
return new InnerClass("访问内部类构造方法");
}
//内部类
private class InnerClass implements OutInterface{
InnerClass(String s){ //内部类构造方法
System.out.println(s);
}
public void f() { //内部类实现接口方法
System.out.println("访问内部类中的f()方法");
}
}
}
//主方法
public class InterfaceInner {
public static void main(String[] args) {
OuterClass2 out = new OuterClass2(); //实例化一个外部类对象
OutInterface outinter = out.doit(); //调用外部类的doit()方法,返回一个接口,
outinter.f();
}
}
如果某个类继承了外部类,由于内部的权限不可以向下转型为内部类InnerClass,同时也不能访问f()方法,但是却可以访问接口中的f()方法。
非内部类不能被声明为private或protected访问类型。 |
如果在外部类中定义的成员变量与内部类的成员变量相同时,可以使用this关键字。具体见代码注释:
public class TheSameName{
private int x = 0;
public String getXOut() {
return String.valueOf(x);
}
private class Inner{
private int x = 9;
public String doit(int x) {
x++; //调用的是形参x
this.x++; //调用内部类的变量x
TheSameName.this.x++; //调用外部类的变量x
return String.valueOf(x);
}
public String getXIn() {
return String.valueOf(x);
}
}
public static void main(String[] args) {
TheSameName tsnOut = new TheSameName();
TheSameName.Inner in = tsnOut.new Inner();
System.out.println(in.doit(6)); //7
System.out.println(tsnOut.getXOut()); //1
System.out.println(in.getXIn()); //10
}
}
在内存中所有对象均被放置在堆中,方法以及方法中的形参或局部变量放置在栈中。
2. 局部内部类
在类的方法或任意的作用域中均可以定义内部类
interface OutInterface2{ //定义一个接口
}
public class OutClass3{
public OutInterface2 doit(final String x){
//在doit()方法中定义一个内部类
class InnerClass2 implements OutInterface2{
InnerClass2(String s){
s = x;
System.out.println(s);
}
}
return new InnerClass2(x);
}
public static void main(String[] args) {
OutClass3 out = new OutClass3();
out.doit("doit");
}
}
内部类InnerClass2是doit()方法的一部分,并非OuterClass3类中的一部分,所以在doit()方法的外部不能访问该内部类,但是该内部类可以访问当前代码块的常量以及此外部类的所有成员。
**将doit())方法的参数设置为final类型**
如果需要在方法体中使用局部变量,该局部变量需要被设置为final类型。换句话说,在方法中定义的内部类只能访问方法中final类型的局部变量。
三、匿名内部类
四、静态内部类
(不想写了……以后再补)