Java开发知识之Java类的高级特性,内部类.以及包使用.跟常量关键字
一丶Java中包的机制
首先包其实就是个文件夹.作用就是管理类. Java中每次定义一个类的时候.通过Java编译之后.都会生成一个扩展名为.class的文件.但是当这个程序规模逐渐庞大的时候.就很容易发生类名名称冲突的现象. 那么JDK API中. 提供了成千上万的具有各种功能的类.有效的管理就是通过类包来管理.
1.类名冲突
首先我们Java中可能定义一个A类.但是因为业务需要.还需要一个A类.名称一样,可能功能不一样.那么名字就会冲突.而Java编译器不允许存在同名的类文件.解决方法
就是放在不同的文件夹中(包中)
2.完整的类路径
在以前我们使用Math类.eclipse会自动引入一个包.关键字就是 import 包. 我们当时也不注意.反正能编写程序即可. 其实Math类.完整的路径是 Java.lang.math;
java.lang 是包的名称,可以理解为是文件夹. 后面的math是类名. 我们使用 import java.lang.Math 代表的意思就是 使用这个文件夹下指定的Math类.
我们如果不使用关键字 import引入包. 那么就要使用完整的类名 例如: java.lang.Math ma = new java.lang.Math();
注意:
1.同一个包中的类互相访问的时候,可以不指定报名.
2.同一个包中的类可以不用放在一个磁盘.什么意思. java.lang 是报名. 我们可以在D盘创建一个 java.lang E盘我们也创建一个java.lang 此时我们只需要CLASSPATH指向这两个包就行.包他认为就是一个.都属于java.lang包. 这跟文件夹不太一样.
3.创建包.
我们可以使用Eclipse创建一个包. 新建->包. (new -> packet)
填写文件夹. 以及包名称即可.
创建完毕之后就有一个包了.在我们的项目中.
package 关键字
package 包名.
我们在类中指定包名的时候.需要将package表达是放置在程序的第一行. 他必须是文件中第一行.并且是非注释代码. 如果指定了包名称.那么代表这个类的完整路径就是
包名.类名称. 例如 com.aaa是我们的包. 在下面定义了一个类. Dog() 那么Dog类的完整路径就是 com.aaa.Dog();
例如:
4.导入包
我们上边虽然定义了包.但是使用的时候我们必须指定完全的类名去创建对象.例如如下:
我们不能每次new对象的时候都要加上包的名称.所以我们可以使用关键字.导入包.这样使用的时候直接给定类名即可.
import关键字.
语法:
import 包名.通配符.
例如: import com.xxx.Math 也可以 import com.xxx.*; 表示导入这个包中所有的类.
注意:如果你有两个相同类.你要使用那个类.就要加上完整的类名去使用. 这个便于区分. java中的类包.类似于C++的命名空间.都是解决冲突问题.
5.Import的高级用法
Import不光可以导入类包.也可以导入静态变量.这个是 J2SE 5.0以上才支持的.
关键字:import static 包名+静态成员变量 代码如下.
二丶Final关键字的作用
Final关键字是常量定义关键字. 他可以修饰类 方法. 以及变量跟引用.
变量:
1.修饰变量
1.修饰变量. 变量不可以修改.成了一个常量. 例如 final double PI = 3.14; 此时PI我们只可以访问而不能修改了.在修饰变量的时候应该直接进行初始化.
C++ 则是在类外面加上类域进行初始化 const int 类名::变量 = 初始化的值;
在Java类中如果只定义了final成员变量.那么初始化可以在构造函数中进行初始化.
空白final成员变量初始化
.2.final 修饰对象
final修饰对象.则对象只能指定唯一的一个对象.且不能修改.
如果修饰数组.则数组里面的值可以修改.但是数组对象不能指向别的数组了.
如下.:
3.final与static的使用
final 修饰的变量.初始化的时候可以使用随机数进行初始化.这样常量的值就是可以改变的.但是如果加上Static关键字.那么意思就是其内存区域是恒定不变的.所以值不会被改变了.
代码如下:
public class Cat { private static Random r = new Random(); public final int a = r.nextInt(10); //常量a
public final static int b = r.nextInt(10); //静态区域的常量b
public Cat() { }
public void eat() {
System.out.println("猫在吃饭");
};
}
使用
public static void main(String[] args) {
Cat c = new Cat();
out.print("a = " + c.a);
out.println(" b = " + c.b); Cat b = new Cat(); out.print("a = " + b.a);
out.print(" b = " + b.b);
}
输出结果
可以看出.我们对象中final修饰的a也就是变量a随机数可以进行改变的.但是b因为是static所以不能被改变了.
在Java中 定义全局变量一般都是用 public static final 修饰. 这样修饰的只能在定义的时候并且初始化.可以这样使用.
方法:
1.父类方法private + final修饰
以前我们知道.当父类中的方法 使用private修饰的时候.则子类继承父类的时候.则不能覆盖(重写)
而将方法使用final修饰的话.可以防止子类修改该类的定义与实现方式. 所以父类中使用private修饰的时候.
方法自然地加上了默认修饰符 final. 因为final修饰的方法效率远高于非final的方法.
注意下方代码:
父类:
public class Anmail { final private void eat1() {
System.out.println("父类吃1");
}
final public void eat2() {
System.out.println("父类吃2");
}
}
子类:
public class Dog extends Anmail implements IAnmail{ public final void eat1() {
System.out.println("子类吃1");
} public final void eat2() {
System.out.println("子类吃2");
} @Override
public void Play() {
// TODO 自动生成的方法存根 } }
我们可以看到.我们子类竟然可以 "覆盖父类方法" 并且权限已经改为public 请注意.这个并不是覆盖.而是子类的一个新的方法.
跟父类的方法不一样.也没有进行重写.
final类
final修饰的类则不能被继承了.
语法:
final class 类名{}
三丶类的高级特性.内部类.
在java中.类中可以使用内部类.意思就是在一个类中还可以定义一个类.
1.成员内部类
成员内部类就是定义一个成员.这个成员就是一个内部类.
例如:
public class A{
private class B{
.....内部类代码.
}
}
其中 A是外部类. B是内部类.
B内部类可以随意使用外部类的成员变量以及成员方法. 不管这些类是否被修饰为private.
在外部类可以new 内部类.使用内部类.
例如:
public class A{
class B{
....
}
B b = new B(); 使用内部类
}
内部类的使用:
内部类的实例化跟外部类一样.只不过你是内部类我们跟Java类包一样. 加上外部类名即可. 但是在new的时候有区别.
new的时候要在外部类中提供一个方法.这个方法专门是返回内部类的实例化对象.
public class Cat { public class Cat1{
public int m_hande;
public void eat() {
System.out.println("内部类吃东西");
}
}
Cat1 retInstance(){ //专门提供一个方法.进行返回成员内部类的实例化对象.
return new Cat1();
}
}
使用:
public static void main(String[] args) {
Cat c = new Cat(); //创建外部类对象
Cat.Cat1 b = c.retInstance(); //外部类的方法返回内部类实例 b.eat();
}
或者使用以下方法.
public static void main(String[] args) {
Cat c = new Cat();
Cat.Cat1 b = c.new Cat1();//使用new b.eat();
}
这里注意的就是一定要创建出外部类对象才可以使用内部类.
1.外部类方法返回内部类实例.
2.外部类中直接当成员使用.使用new的方法.new一个. 因为Cat1我们可以看成是一个成员变量.只不过是一个特殊的成员变量.
成员内部类的高级用法
成员内部类可以向上转型为父类. 成员内部类可以实现一个接口.对外隐藏其实现方法.
例如如下;
定义接口:
public interface IAnmail { public abstract void Play(); //定义一个抽象方法
}
父类跟成员内部类
public class Cat { public class Cat1 implements IAnmail { @Override
public void Play() {
// TODO 自动生成的方法存根
System.out.println("内部类玩耍");
} //实现IAnmail方法 }
public Cat1 retInstance(){ //专门提供一个方法.进行返回成员内部类的实例化对象.
return new Cat1();
}
}
可以看到.内部类Cat 实现了接口IAnmail. 并且外部类返回了内部类的实例化对象.
使用:
public static void main(String[] args) {
Cat c = new Cat();
IAnmail b = c.retInstance();//注意此行代码
b.Play(); }
注意第二行代码:
.返回的是内部类实例化对象.使用接口接受.意思就是说向上转型为了父对象.父对象直接使用play方法. 这样可以隐藏内部类的实现细节. 其实本质区别没有变.还是类跟类的关系.
只不过是内部类而已.
这样做的好处是什么: 好处就是一般的类.不能多次实现接口中的方法. 而我们的内部类可以.我们可以写上几个内部类.去实现接口.并且多次实现其方法. 因为向上转型.会触发多态.
所以一个类中可以有不同的事件产生.这个一般用于窗口设计中.Android中好像也是这样.还没接触安卓.不过按照书上所写.应该可以同时监听不同的事件.
this关键字用于内部类跟外部类
我们以前说过.this可以访问构造.也可以区分成员变量与局部变量的命名冲突. 但是此时我们的内部类中有成员的变量.跟外部类中的成员变量相同怎么办.
所以我们必须进行区别.
用一下代码进行区别.
public class Cat {
int x = 0; //外部类的X
public class Cat1 {
int x = 1; //内部类的x
public void eat(int x) {//方法中的形参x
x ++ ; //操作的是方法中的形参x
this.x ++; //操作的是内部类的x
Cat.this.x++;//前边加上外部类名则是操作的外部类的成员变量x }
public class cat2{
int x;
public void eat(int x) {
x++;
this.x++;
Cat1.this.x ++;
Cat.Cat1.this.x++;
}
} }
public Cat1 retInstance(){ //专门提供一个方法.进行返回成员内部类的实例化对象.
return new Cat1();
}
}
首先总结来说.
this用于当前类.那么则是区分的本类的成员变量与形参.
如果this前边加上父类名. 则是操作的父类的成员变量.
下面我们写了内部类的内部类. 使用this的时候就是 都是加外部类名. 只不过类名不一样而已. 依次类推.
2.方法内部类 /局部内部类.
方法内部类就是说.可以定一个方法.这个方法中可以定义一个类去使用.
因为他是属于一个方法的.是一个方法中的类.所以外部类不可以访问局部内部类. 但是内部类可以访问当前代码块的常量以及外部类的所有成员.
代码如下:
public class Cat {
int x = 0; //外部类的X public IAnmail retInstance(){ //专门提供一个方法.进行返回成员内部类的实例化对象. class Cat1 implements IAnmail{ public void Play() {
// TODO 自动生成的方法存根
System.out.println("内部进行玩耍");
} }
return new Cat1(); //返回实例化对象.但是需要用父类进行接收.因为外部没有此类对象
}
}
使用:
public static void main(String[] args) {
Cat c = new Cat();
IAnmail b = c.retInstance();
b.Play(); }
局部内部类很简单.就是方法中定义一个类.而返回的时候可以返回这个类的实例对象.使用父类接受.可以向上转型.
3.匿名内部类.
上面所说的局部内部类.返回的时候是自己new了一个对象进行返回.且外面进行接受了. 我们还可以使用return的时候.字节返回.
就不用类定义了.
代码如下:
public class Cat {
int x = 0; //外部类的X public IAnmail retInstance(){ return new IAnmail() { @Override
public void Play() {
// TODO 自动生成的方法存根
System.out.println("匿名内部类");
} };
}
}
匿名内部类就是跟return语句进行结合了. 还是在方法内部.
以前我们返回的是 new Cat1(); 现在我们知道返回值是一个接口.我们可以直接返回一个接口类.
其实这个类的作用就是返回一个实现接口的对象而已.
语 法: new A () {
....
}
A可以是一个接口. 父类. 向上转型类都可以.
4.静态内部类.
在内部类前边添加修饰符static.那么就是静态内部类. 静态内部类中可以声明static成员.但是不是静态内部类不可以声明静态成员.
特点: 不可以使用外部类的非静态成员. 所以静态内部类开发中很少见.
可以理解为静态内部类加了很多现实.
1.如果创建静态内部类的对象.不需要其他外部类的对象.
2.不能从静态内部类的对象中访问非静态外部类的对象.
5.内部类的继承
如果一个类.想要继承一个内部类.
比如有一个A类.一个B类. B类中有内部类C类.
我们的A类想要继承B中的C类.
那么A类就要提供一个带参构造. 参数是类 B.
且构造参数中需要加上a.super():才可以.
代码如下.
public class AnmailB { public class AnmailC{ }
}
使用一个类继承AnmailC
public class Cat extends AnmailB.AnmailC{
public Cat( AnmailB b) {
b.super();
} }
四丶总结
1).Java中的类包
package 包名 用来定义一个包
import 包名.类名 导入一个包中的某个类. 可以直接使用这个类new对象了.而不用加上完整包路径
2).java中的final变量
final 修饰变量 变量变量变成常量.且不能修改
final 修饰引用. 引用只能指向一个对象.不能更改指向. 但是引用里面的成员变量的值可以修改.
final 修饰数组. 数组里面的值可以改变.地址不能改变了.意思就是不能更改指向了.
final 跟 static一起使用 final 修饰常量.可以被随机数修改值.也就是初始化的时候. 但是加上static则内存是一块不能改变的. 也就是说值被赋值之后.内存里面的值不会在进行改变了.
final 修饰方法. 则方法不能被继承跟重写. private权限.默认加了final关键字.
3).java中的内部类.
1.成员内部类.
成员内部类就是一个成员. 使用的时候外部类提供方法.用来返回内部类的实例化对象.
A.B a = A.retInstance(); 或者 A.B a = A.new B();
成员内部类可以实现接口. 返回的时候可以使用父类接受. 向上转型.隐藏实现细节.
接口 A = A.new B(); 内部类可以实现多个接口中方法.用来监听不同的事件.
2.局部内部类,方法内部类.
定义一个方法.方法中定义一个类.返回的时候可以返回这个类的实例化对象. 返回值可以是 实现的接口.或者父类.向上转型.
3.匿名内部类.
匿名内部类直接返回一个实现接口的对象即可.
例如 return new 接口(){ xxx代码};
4.静态内部类.
静态内部类就是给类加了限制.不能访问外部类的非静态成员. 内部类中只能定义静态成员.
4).this关键字用于内部类
this关键字用于类内部可以区分类的成员变量跟形参区别.
如果想使用外部类.则要加上外部类的类名才可以 外部类名.this.成员变量; 这样使用的就是外部类的成员