>>内部类
定义:分为三种
>>1普通内部类 (和类的方法,成员变量,静态代码块平级),
class TestInner{
public static void main(String[] args){
Outer outer=new Outer(); //要创建内部类 必须先创建 外部类的实例 因为 普通内部类 在外部类的 对象中 (它和类的成员变量平级)
Outer.Inner inner=outer.new Inner(); // 用外部类的实例对象 去创建内部类的实例
inner.name="Inner(内部类)";
inner.fun();
}
}
class Outer{
String name;
static{
}
void fun(){
}
class Inner{//这个类 和外部类中的成员变量 和静态代码块 还有方法平级
String name;
void fun(){
System.out.println(name+"-->哈哈我就是传说中的普通内部类里面的方法 要想用我了 必须要用外部类的实例才能创建我啊");
}
}
}
**特点: 内部类 可以直接访问外部类的 所用东东 包括所用的东西静态的东西也可以 都可以可以直接拿来用
通过 外部类的.this(表示外部类的当前对象) Outer.this.name 表示外部类的成员变量 Outer.this.fun() 表示外部类的成员方法
class Outer{
String name;
static{
}
void fun(){
}
class Inner{//这个类 和外部类中的成员变量 和静态代码块 还有方法平级
String name;
Outer.this.name="OuterName";//在这里 不能直接赋值 一个经典的错误
void fun(){
System.out.println(name+"-->哈哈我就是传说中的普通内部类了");
}
}
}
注意一下:
记住 外部类的对象 不能直接用内部类的对象 因为 在创建外部类的对象之后 可能还没有创建 就算创建了 也不止是一个 jvm 不知道该确定那一个 所用 外部类的对象 不能用内部类对象的东西
如果非得在外部类 使用内部类的成员 可以这样做:
class Outer{
String name;
static int i;
static{
}
void fun1(){
Inner inner=new Inner(); //只有创建了 内部类的对象 在外部类的方法中才可以 使用内部类的 成员
inner.fun(); //然后通过对象来访问内部类的东东
}
class Inner{//这个类 和外部类中的成员变量 和静态代码块 还有方法平级
String name;
//Outer.this.name="OuterName";//在这里 不能直接赋值 一个经典的错误 在方法外面 不能出现赋值语句
void fun(){
Outer.this.i=50;
System.out.println(name+"-->哈哈我就是传说中的普通内部类了");
System.out.println(Outer.this.i);
}
}
}
>>>>>>>>>>>>>>>>>>>>>>>>>必须记住的东西 在类中 不能出现赋值语句 会报错的 在方法中可以 类在 是声明的地方 尽量不要赋值
>>2方法中的内部类(作用域是方法的大括号,在外部不能创建实例 只能在方法中创建..),
class Outer{
void fun(){
class Inner{
String name="MethodInner";
void funMethodInner(){
System.out.println("我是方法内部类中的方法");
}
}
Inner inner=new Inner();//会先查找 方法中的类 如果找不到 会查找外部类中的普通内部了 如果还找不到 回去 找别的类 如果还没有报错..
inner.funMethodInner();
}
class Inner{
void funMethodInner(){
System.out.println("我是一个普通的内部类 如果没有方法内部类才会调用我");
}
}
}
class Inner{
void funMethodInner(){
System.out.println("我是一个普通的类 在方法内部类中 如果没有 方法内部类 和 普通内部类 才会调用我 我是最后一个被调用");
}
}
方法中的内部类必须先定义再使用, 定义的代码必须在使用的代码上面.
因为方法是从上到下运行的, 需要先运行到定义类的代码, 后面才能使用.
因为内部类对象的生命周期有可能比局部变量生命周期要长. 局部变量在方法结束的时候, 就会被销毁. 而内部类对象仍然可能有其他引用到达.
为了在这种情况下不出错, 需要将局部变量的生命周期延长, 所以使用final修饰.
方法中的内部类访问方法中局部变量, 变量必须声明为final.
>>>.在方法内部类中不能直接访问方法中的局部变量
原因: 因为内部类的对象的生命周期可能会比局部变量的生命周期要长, 局部变量在方法结束的时候 就会被销毁, 而内部类的对象仍然可能有其他引用
如果在方法内部类中非得 访问方法中的局部变量 可以巴局部变量 变成final 声明位final的局部变量 就是常量
class Outer{
void fun(){
int x=98;
class Inner{
String name="MethodInner";
void funMethodInner(){
System.out.println("我是方法内部类中的方法");
System.out.println(x);//这样写会直接报错
}
}
Inner inner=new Inner();
inner.funMethodInner();
}可以改为: 只改了一个final
class Outer{
void fun(){
final int x=98;//加个final 就表示这个局部变量 是常量 在内存中会存在很久很久...
class Inner{
String name="MethodInner";
void funMethodInner(){
System.out.println("我是方法内部类中的方法");
System.out.println(x);//这样写会直接报错
}
}
Inner inner=new Inner();
inner.funMethodInner();
}
>>3静态内部类 (不需要创建内部类实例 直接通过外部类.内部类 就可以调用)
内部类最大的特点就是 不用创建内部类对象 而在普通外部类 中必须 通过一个外部类的实例 才能创建普通内部类
>>.>在静态内部类 中不管是不是静态方法 都不能调用外部类的非静态 方法
因为静态的东西 没有在堆空间 也没有在栈 它有特定的取余叫静态区域 在静态区域块里面只能访问静态的东西 一切非静态的东西都不能用....
因为静态内部类可以在不创建外部类的情况下创建对象, 没有外部类对象, 就不能调用外部类的成员
>>>面向的第二大特性 继承..
java不支持多继承 但支持多重继承 一个子类 只能调用 重写爹类的重写方法 不能调用爷类的被爹重写的方法
继承 的一些基本概念就不总结 了 谁都知道~~
>>>>类型转换
>>>>基本类型的比较
普遍的一个规定 大的东西 能装下小的东西 一个int 能装下一个byte 所以 声明是int 实际装的是byte 不会报错 这叫自动类型转换
而声明是byte 非得装 int的东西 就必须 把 int的值 砍掉一多半 躲碎了 在装到byte的小容器里面 这就 暴力转换 也叫强制类型转换 会损失精度
>>>>>引用类型的比较
自动类型转换:
class Test{
public static void main(String[] args){
byte b=15;
int i=b;//值类型的自动转换
Teacher t=new Teacher();//这个也叫做自动类型转换 在这种情况下: 父类比子类大 但是在内存中 子类明显比父类大很多
Person p=t;//这个叫什么? 这个就是把 t的地址 给了 p变量 这样 p变量 就指向了 Teahcer这个大的堆内存 p变量里面存储的就是Teacher的地址 而不是Person类的地址
}
}
class Person{
}
class Teacher extends Person{
}
强制类型转换
class Test{
public static void main(String[] args){
int i=15;
byte b=(byte)i;//值类型的强制类型转换 把int 后面的东西都砍掉了
Person p=new Person();// 做什么的东西 都要看new后面的实例 在创建对象的时候 千万不要用父类的实例 这个很严重的错误
Teacher t=(Teacher)p;//如果不加Teacher会报错 就算你加上了Teacher 还是会报错 在jvm它有一种绑定机制 它会自动的把T变量 指向 Teacher(子类)的堆空间 是无法指向父类的
}
}
class Person{
}
class Teacher extends Person{
}
可以改为:
class Test{
public static void main(String[] args){
Person p=new Teacher();//这个叫做父类的引用指向子类的实例 现在p变量里面存的就是父类的地址
Teacher t=(Teacher)p; //然后强制把父类的地址变成子类的地址 这样就可以调用子类中父类没有的方法了
}
}
class Person{
}
class Teacher extends Person{
}
在这里就出现了一个很严重的问题 如果 那两片空间 不是在一块 就不能强制转换了 可以通过instanof来判断
语法是 p instansof Person 或者t instanesof Teacher 前面放的是地址 后面放的是 类名
在向上转型时, 使用父类变量引用子类对象, 不能调用子类特有方法, 如果一定要调用, 那么可以强制类型转换.
使用 (类型) 的形式将一个父类变量转换为子类变量.
在强制类型转换的时候, 编译器无法判断被转对象的类型. 这时如果被转对象不能强制转换为要转的类型, 运行时会报错.
为了避免这种错误, 我们一般在强转之前都要使用 instanceof 来判断一下要转的对象是否是指定类型.
向上转型时遇到的问题
在子类当做父类来用的时候, 用父类变量记住一个子类对象.
这种情况下, 使用父类变量调用方法, 会调用子类的方法, 因为这个变量中记住的是子类对象的地址. JVM虚拟机的动态绑定.
而这种动态绑定的机制没有被使用到类的属性中, 因为java希望我们将所有的属性私有化, 也就不会被继承, 就不会出现这种问题.
>>.匿名内部类
1.什么是匿名内部类
如果一个类只使用一次, 那么就可以使用匿名内部类.
2.定义的格式
new 父类类型(){
类定义
}
这样做是做了两件事, 先定义了一个类继承于指定父类, 然后使用这个类创建了一个对象
class Test{
public static void main(String[] args){
Person p=new Teacher();
Teacher t=(Teacher)p;
System.out.println(t instanceof Person);//这个意思是 看 这个 t 是不是一个Person的实例
System.out.println(p instanceof Teacher);//全对
}
}
class Person{
}
class Teacher extends Person{
}