------- android培训、java培训、期待与您交流! ----------
1.面向对象之内部类
内部类顾名思义,是定义在内部类中的类,又叫做嵌套类,内部类的主要作用是将逻辑上相关的类放在一起,这样跟符合客观规律,为什么这么说呢,内部类大体上分为三种.1).非静态内部类
2).静态内部类
3).匿名内部类
我们现在第一个说非静态内部类,非静态内部类声明在外部类的成员变量的位置上,想创建内部类的对象实例,必须先创建外部类实例,在生活中经常有这样的情况,比如说,中国人出身下来,作为一个合法的天朝公民必须要有个身份证,(干什么事都方便些吗),你去jc局办理身份证必须要指定给谁办理一张身份证,身份证不可能脱离一个人存在,你不会说给一个不存在的人办理一个身份证,这时候就应该将身份证这个类写在Person类的里面,不允许身份证对象脱离一个人创建出来.非静态内部类得注意以下几点
1.创建一个非静态内部类必须要有一个外部类的对象,也就是说,有内部类对象,必然有一个外部类对象,但反过来,有外部类对象不一定会有内部类对象,用new外部类.new内部类创建内部类实例
2.因为创建内部类必须依赖外部类,所以,有个误区,就是千万不要认为,内部类的父类是外部类,内部类与外部类没有继承关系,内部类能访问外部类中的方法和变量是因为内部中有一个外部类的引用,他能找到外部类的对象,这样做不报错是因为内部类当中你调用某个方法时,内部类中如果没有的话他会去外部类中找,而外部类此时一定被实例化了.所以不会有问题.
3.在内部类中的非静态方法中,this 这个关键字使用时得注意,在内部类中使用 this.方法名(方法参数)调用某个方法时或使用 this.变量名,他只会在当前对象中去找,不会到外部类中去找,所以你如果想他在本类中找不到方法时去外部类中去找,应该把 this 略去,直接写方法名(方法参数)或变量名
4.内部类(这里指的是非静态内部类)不能有 static 修饰的数据,包括静态方法,静态代码块,静态成员变量,前段时间,刚学完面向对象时,我还是一直搞不懂内部类的机制,直到后来学到反射,知道什么是类加载器,什么是.class 文件,什么是字节码文件,我重看内部类时,突然之间就顿悟了,java中有句话叫做 static 修饰的数据,必须在字节码文件被加载进内存时执行, 绝对不能在创建对象的时候执行.你如果将内部类声明为非静态的,又在内部类中放一些静态数据,这时候,问题就出来了,因为你如果在非静态内部类中定义了静态数据,这时候内部类的字节码文件只有在创建外部类对象时,内部类的字节码文件才加载进内存,静态数据得到执行,但是这和java的思想相违背,变成了创建对象时,静态数据得以执行,矛盾了.
5.最后一点就是关于外部类和内部类方法名和成员变量名称尽量不要相同,外部类和内部类方法不存在重载和覆写,你如果在外部类和内部类中声明了相同的变量名称的话,如果想用内部类中的变量直接this.变量名即可,如果想使用外部类中的变量的话,得使用 外部类名.this.变量名 才能访问.下面我们来写程序验证以上几个问题吧
6.内部类和外部类还有一个区别就是外部了的权限修饰符只有 public 和 default 两种,内部类则四种都能够修饰
实例代码
public class TestOuterClass {
private String name = "TestOuterClass";
private int age = 15;
public static void main(String[] args) {
//无法脱离外部类直接创建内部类对象
//InnerClass i1 = new InnerClass();
InnerClass i2 = new TestOuterClass().new InnerClass();
i2.println();
}
public void println(int i) {
System.out.println("outer");
}
class InnerClass {
//静态成员变量编译无法通过
//static int num = 1;
private String name = "InnerClass";
public void println() {
System.out.println("内部类的name" + name);
System.out.println("外部类的name" + TestOuterClass.this.name);
//this.age无法找到age变量,编译无法通过,this代表子会在内部类中找,应该把this去掉
//this.age;
age = 13;
//这句话无法编译通过,无法找到方法,内部类和外部类不存在重载
//println(2);
//得用这种方式
TestOuterClass.this.println(3);
}
}
}
这个程序中我注释掉的地方就是内部类容易出错的地方.
接下来说第二种内部类,静态内部类
理解了非静态内部类,静态内部类就很好理解了,外部类对于非静态内部类来说,很重要,非静态内部类比外部类要矮上一级,但是静态内部类与外部类的联系就没有非静态内部类与外部类联系那么紧密,静态内部类和外部类是同一级别上的,静态内部类的字节码是随着外部类的字节码加载,所以不会出现像非静态内部类那样的问题,就是内部类中不能存在静态数据的问题
使用静态内部类得注意以下几点
1.静态内部类的方法中不能出现外部类名.this.方法名或成员方法这种语句
2.静态内部类只可以访问外部类的静态数据,和静态方法
3.如果在外部类的main()方法中穿件静态内部类的实例只需要内部类名.变量名 = new 内部类名,因为这时候静态内部类的字节码文件已经加载了,如果在另一个类中的方法中想要创建
静态内部类的对象的话,得使用 外部类名.内部类名 变量名 = new 外部类名.内部类名 这种语法格式,这种方式是为了确保内部类的字节码文件一定会被加载.
实例代码
public class TestOuterClass {
private String name = "TestOuterClass";
private static int age = 15;
public static void main(String[] args) {
//无法脱离外部类直接创建内部类对象
//InnerClass i1 = new InnerClass();
InnerClass i2 = new InnerClass();
i2.println();
}
public void println(int i) {
System.out.println("outer");
}
static class InnerClass {
static int num = 1;
private String name = "InnerClass";
public void println() {
System.out.println("内部类的name" + name);
//System.out.println("外部类的name" + TestOuterClass.this.name);
//this.age无法找到age变量,编译无法通过,this代表子会在内部类中找,应该把this去掉
//this.age;
age = 13;
//这句话无法编译通过,无法找到方法,内部类和外部类不存在重载
//println(2);
//得用这种方式
//TestOuterClass.this.println(3);
}
}
}
class TestInner {
public void newInner() {
TestOuterClass.InnerClass i2 = new TestOuterClass.InnerClass();
}
}
下面就是匿名内部类的
如果有一个类想要实现某个接口的话或者继承某个抽象类,首先必须写一个内部类或者外部类,实现指定的接口或者继承抽象类,但是你确定这个类的对象我只是使用一次,那你如果嫌麻烦的话可以不定义类来继承别的抽象类类或实现接口,有另外一种更加简单的方法,使用匿名内部类.匿名内部类咋看之下打破了java的规则,java明确规定不允许使用 new 关键字创建抽象类或者接口的对象,但匿名内部类就这么干了,而且干得很好.下面通过代码来看看他是怎么一回事
实例代码
public class TestNoNameClass {
public static void main(String[] args) {
new Teacher(){
public void study() {
System.out.println("老師可以学习新知识");
}
public void teach() {
System.out.println("老師教授知识");
}
}.study();
}
interface Teacher {
public abstract void study();
public abstract void teach();
}
}
这段代码很简单,定义了一个内部接口,之后创建了一个接口对象,但是接口是不能创建对象的,我们只好在接口后面加上一个大括号,在大括号中实现接口的抽象方法,这就相当与申明了一个类,该类实现了指定的接口,并重写类接口中的方法,只是该类没有名字,所以叫匿名内部类,没有名字,所以只能使用一次,想创建第二个匿名内部类对象的话只有再次重写接口中的方法说道这里,我再来谈一下,关于java中类的继承的事,之前我说过java不知此多继承,可以考虑使用实现多个接口的方法来弥补单继承的局限性,但是实现是实现,继承是继承,你如果硬是要用继承的话,也不是不可以,这不,内部类就弥补了这个缺陷,你如果想要继承两个类的话,可以使用外部类继承一个类内部类又继承一个类,因为内部类中能访问外部类中的数据,所以,你可以把内部类理解成继承了两个类.但是感觉还不是太好用,如果要继承三个类的话,就要有三层类了,或者第二套方案,假如你有A,B,C,D四个类,想让A类继承B,C,D三个类.你可以把A类变成外部类B类的非静态内部类,外部类B类继承D类,内部类A类又继承C类,这样只用了一个内部类就同时继承了三个类,算了,看一下代码吧
实例代码
public class B extends D {
String name = "B";
public static void main(String[] args) {
A var1 = new B().new A();
var1.print();
B var2 = var1.returnB();
}
public void printB() {
System.out.println("B");
}
public class A extends C {
String name = "A";
public void printA() {
System.out.println("A");
}
public void print() {
this.printA();
this.printC();
B.this.printB();
B.this.printD();
}
public B returnB() {
return B.this;
}
}
}
class C {
String name = "C";
public void printC() {
System.out.println("C");
}
}
class D {
String name = "D";
public void printD() {
System.out.println("D");
}
}
你看,就使用了一个内部类的对象,就使其他三个类中的方法都能得到执行了.
2.关于java中变量的命名
java中的变量,包括类名,方法名,变量名,常量名,包名,接口名,参数名可由任意的大小写字母,数字,下划线,美元符号组成,但不能使用数字开头,还有不能使用java中保留的关键字
给变量起名字注意以下几点
1.类名,接口名第一个字母大写,
2.方法名第一个字母小写,变量名,参数名也是
3.常量要全部字母大写,单词与单词之间用"_"分隔
4.变量命名需遵循驼峰标识,就是新单词第一个字母要大些,常量除外,
这些规则不是强制性的,是程序员之间约定成俗的规则,别人都这样,你也不好打破.