JAVA核心学习:类的高级特性

1. Java 类包

1.1 类名冲突

Java中每个接口或类都来自不同的类包,无论是Java API中的类与接口还是自定义的类与接口都需要隶属某一个类包,这个类包包含了一些类和接口。如果没有包的存在,管理程序中的类名称也是一件非常麻烦的事情,如果程序只由一个类定义组成,那么这并不会给程序带来什么影响,但是随着程序代码的增多,难免会出现类同名的问题。例如,在程序中定义一个Login类,而因业务需要,还要定义一个名称为Login的类,但是这两个类所实现的业务完全不同,于是问题就产生了,编译器不会允许存在同名的类文件。解决这类问题的办法是将这两个类放置在不同的类包中。

1.2 完整的类路径

一个完整的类名需要包名与类名的组合,任何一个类都隶属于一个类包,只要保证同一类包中的类不同名,就可以有效地避免同名类冲突的情况。

1.3 创建包

语法如下:

package 包名

在类中指定包名时,需要将package表达式放置在程序的第一行,它必须是文件中的第一行非注释代码。

使用package关键字为类指定包名之后,包名将会成为类名中的一部分,预示着这个类必须指定全名。

注意:Java包的命名规则是全部使用小写字母。

1.4 导入包

1.4.1 使用import关键字导入包

在这里插入图片描述
使用ctrl+shift+o,快速导入所有需要的包。

1.4.2 使用import导入静态成员

在这里插入图片描述

2. final 变量

final关键字可用于变量声明,一旦该变量被设定,就不可以再改变该变量的值。通常,由final定义的变量为常量。

final关键字定义的变量必须在声明时对其进行赋值操作。final除了可以修饰基本数据类型的常量,还可以修饰对象引用。由于数组也可以被看作一个对象来引用,所以final可以修饰数组。一旦一个对象引用被修饰为final后,它只能恒定指向一个对象,无法将其改变以指向另一个对象。一个既是static又是final的字段只占据一段不能改变的储存空间。

被定义为final的常量定义时需要使用大写字母命名,并且中间使用下划线进行连接,这是Java中的编码规则。同时,定义为final的数据无论是常量、对象引用还是数组,在主函数中都不可以被改变。

import java.util.Random;

public class FinalStaticData {
	
	private static Random rand = new Random();
	private final int a1 = rand.nextInt(10);
	private final static int a2 = rand.nextInt(10);
	
	public static void main(String[] args) {
		FinalStaticData fdata = new FinalStaticData();
		System.out.println("重新实例化对象调用a1的值:"+fdata.a1);
		System.out.println("重新实例化对象调用a2的值:"+fdata.a2);
		
		FinalStaticData fdata2 = new FinalStaticData();
		System.out.println("重新实例化对象调用a1的值:"+fdata2.a1);
		System.out.println("重新实例化对象调用a2的值:"+fdata2.a2);
		
	}
	

}

得到结果:

重新实例化对象调用a1的值:4
重新实例化对象调用a2的值:9
重新实例化对象调用a1的值:6
重新实例化对象调用a2的值:9

可以看出,定义为final的常量(a1)不是恒定不变的,但是如果声明为static final形式(a2),就在内存中开辟了一个恒定不变的区域。因此,在Java中定义全局常量,通常使用public static final修饰,这样的常量只能在定义时被赋值。

3. final 方法

定义为final的方法不能被重写。

将方法定义为finall类型可以防止任何子类修改该类的定义与实现方式,同时定义为final的方法执行效率要高于非final方法。在修饰权限中曾经提到过private修饰符,如果一个父类的某个方法被设置为private修饰符,子类将无法访问该方法,自然无法覆盖该方法,所以一个定义为private的方法隐式被指定为final类型,这样无须将一个定义为private的方法再定义为final类型。

4. final 类

定义为final的类不能被继承。如果希望一个类不被任何类继承,并且不允许其他人对这个类进行任何改动,可以将这个类设置为final形式。语法如下:

final 类名{}

如果将某个类设置为final形式,则类中的所有方法都被隐式设置为final形式,但是final类中的成员变量可以被定义为final或非final形式。

final class FinalClass {
	int a = 3;
	void doit() {
	}
	public static void main(String[] args) {
		FinalClass f = new FinalClass();
		f.a++;
		System.out.println(f.a);
	}

}

结果:4

5. 内部类

在类体里面定义一个类,这个类就是内部类。内部类可分为:成员内部类、局部内部类、静态内部类以及匿名内部类。

5.1 成员内部类

5.1.1 成员内部类简介

在一个类中使用内部类,可以在内部类中直接存取其所在类的私有成员变量。成员内部类语法如下:

public class OuterClass {
	private class Innerclass{
	//...	
	}
}

在内部类中可以随意使用外部类的成员方法以及成员变量,尽管这些类成员被修饰为private。内部类的实例一定要绑定在外部类的实例上,如果从外部类中初始化一个内部类对象,那么内部类对象就会绑定在外部类对象上。内部类初始化方式与其他类初始化方式相同,都是使用new关键字。

public class OuterClass {
	innerClass in = new innerClass();

	public void outf() {
		in.inf();
	}

	private class innerClass {// 成员内部类
		int y = 0;

		public innerClass() {

		}

		public void inf() {
			System.out.println("内部类方法y=" + y);
		}
	}

	public static void main(String[] args) {
		OuterClass d = new OuterClass();
		d.outf();
		OuterClass.innerClass in = d.new innerClass(); //  实例化内部类对象
		in.inf();
	}

}

结果:

内部类方法y=0
内部类方法y=0 

内部类可以访问它的外部类成员,但内部类的成员只有在内部类的范围内是可知的,不能被外部类使用。

注意:如果在外部类和非静态方法之外实例化内部类对象,需要使用外部类。内部类的形式指定该对象的类型。
内部类对象会依赖于外部类对象,除非已经存在一个外部类对象,否则类中不会出现内部类对象。

5.1.1 内部类向上转型为接口

如果将一个权限修饰符为private的内部类向上转型为其父类对象,或者直接向上转型为一个接口,在程序中就可以完全隐藏内部类的具体实现过程。可以在外部提供一个接口,在接口中声明中一个方法。

interface OutInterface {// 定义一个接口
	public void f();
}

public class InterfaceInner {
	public static void main(String args[]) {
		OuterClass2 out = new OuterClass2();// 实例化一个OuterClass2对象
		// 调用doit()方法,返回一个OutInterface接口
		OutInterface outinter = out.doit();
		outinter.f();
	}
}

class OuterClass2 {
	// 定义一个内部类实现OuterInterface接口
	private class InnerClass implements OutInterface {
		InnerClass(String s) {// 内部类构造方法
			System.out.println(s);
		}

		public void f() {// 实现接口中的f()方法
			System.out.println("访问内部类中的f()方法");
		}
	}

	public OutInterface doit() {
		return new InnerClass("访问内部类构造方法");
	}
}

结果如下:

内部类方法y=0
内部类方法y=0

注意:非内部类不能被声明为private或protected访问类型。

5.1.3 使用this关键字获取内部类与外部类的引用

如果在外部类中定义的成员变量与内部类的成员变量名称相同,可以使用this关键字。

例子:

public class TheSameName {
	private int x;

	private class Inner {
		private int x = 9;

		public void doit(int x) {
			x++;// 调用的是形参x
			this.x++;// 调用内部类的变量x
			TheSameName.this.x++;// 调用外部类的变量x
		}
	}

}

在内部类中使用this.x语句可以调用内部类的成员变量x,而使用TheSameName.this.x语句可以调用外部类的成员变量x,即使用外部类名称后跟一个点操作符和this关键字变可以获取外部类的一个引用。

5.2 局部内部类

局部内部类就是在类的方法中定义的内部类,它的作用范围也是在这个方法体内。

public class Demo {
	public OutInterface action(String x) {

		class innerClass2 implements OutInterface {
			public innerClass2(String s) {
				s = x;
				System.out.println(s);
			}
		}
		return new innerClass2("do");
	}

	public static void main(String[] args) {
		Demo d = new Demo();
		d.action("局部内部类");
	}

}

interface OutInterface {

}

结果

局部内部类

5.3 匿名内部类

语法如下:

return new A(){
	...//内部类体
};

其中,A指类名。在匿名内部类定义结束后,需要加分号进行标识,这个分号不代表内部类的结束,而是代表A引用表达式的创建。

实质上,这种内部类的作用就是创建一个实现与A接口的匿名类的对象。

5.4 静态内部类

在内部类前添加修饰符static,这个内部类就变为静态内部类。一个静态内部类中可以声明static成员,但是在非静态内部类中不可以声明静态成员。静态内部类有一个最大的特点,就是不可以使用外部类的非静态成员,所以静态内部类在程序开发中比较少见。

可以这样认为,普通的内部类对象隐式地在外部保存了一个引用,指向创建它的外部类对象,但如果内部类被定义为static时,它应该具有更多的限制。静态内部类具有以下两个特点:

  • 创建静态内部类的对象,不需要其外部类的对象。
  • 不能从静态内部类的对象中访问非静态外部类的对象。
public class Demo {
	int x = 100;

	static class innerClass4 {
		public static void main(String[] args) {// 可以在静态内部类中运行main方法
			System.out.println("我是静态内部类");
		}
	}
}

5.5 内部类的继承

内部类也和其他普通类一样可以被继承,但是继承内部类比继承普通类要复杂一些,需要设置专门的语法进行继承。

public class Demo {
	
	class innerClass{// 成员内部类
		
	}
	
	public static void main(String[] args) {
		
	}
}

class NewClass extends Demo.innerClass{
	public NewClass(Demo d) {
		d.super();
	}
}

在某个类继承内部类时,必须硬性给予这个类一个带参数的构造方法,并且该构造方法的参数为需要继承内部类的外部类的引用,同时在构造方法中使用a.super()语句,这样才为继承提供了必要的引用对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值