1:内部类(理解)
(1)把类定义在一个类的内部。
(2)特点:
A:内部类可以直接使用外部类的成员,包括私有。
B:外部类要使用内部类成员,必须创建对象使用。
例子:
public class InnerClassTest { public static void main(String[] args) { OuterClass.InnerClass inner=new OuterClass().new InnerClass();//创建内部类对象 inner.innerMethod(); //外部类要使用内部类成员,必须创建对象使用 } } class OuterClass{ //成员变量 private int age=10; //构造方法 public OuterClass(){} //成员内部类 class InnerClass{ public void innerMethod(){ System.out.println("我是成员内部类,访问外部类的私有属性age:"+age); //内部类可以直接使用外部类的成员,包括私有。 } } }
(3)内部类的分类:
局部内部类:定义在方法中的内部类
成员内部类:定义在类中方法外的内部类
(4)成员内部类
class Outer {
class Inner { //成员内部类
}
}
普通的修饰的时候:
外部类名.内部类名 变量 = 外部类对象.内部类对象;
Outer.Inner oi = new Outer().new Inner();
class Outer {
static class Inner {
void method(){}
}
}
用静态修饰内部类时:
外部类名.内部类名 变量 = 外部类名.内部类对象
Outer.Inner oi = new Outer.Inner();
Outer.Inner oi = Outer.new Inner(); //错误
用静态修饰内部类和方法时:
Outer.Inner.method()
成员内部类:
private:为了数据的安全。可以加数据校验
static:为了方便调用。
例子:
/* 成员内部类: 内部类定义在成员位置 内部类对象创建: Outer.Inner x = new Outer().new Inner(); */ class Demo8 { public static void main(String[] args) { //Inner inner = new Inner(); //内部类对象不可以直接这样创建 //System.out.println(new Outer().age); //调用错误 Outer out = new Outer(); Outer.Inner inner = out.new Inner(); //创建内部类对象的方式1 Outer.Inner inner2 = new Outer().new Inner();//创建内部类的对象的方式2 inner.innerMethod(); inner2.innerMethod(); } } class Outer { //成员属性 private int age; //成员内部类 class Inner { public void innerMethod(){ System.out.println("我是内部类的方法,外部类age的值为"+age); //可以直接访问外部私有属性 } } //成员方法 public void outerMethod(){ Inner inner = new Inner(); //创建成员内部类对象,调用成员内部类方法 inner.innerMethod(); } }
/* private与static修饰符的成员内部类 private:外界无法直接创建内部类对象,外部类可以创建内部类对象,在此之前可以加入校验。 static: 修饰内部类,不需要使用外部类对象,外部类名直接调用,修饰内部类成员,不需要内部类对象,使用内部类名直接调用。 */ class Demo9 { public static void main(String[] args) { /*private----------------------------------------------------------------------- //当使用private修饰成员内部类,则不能使用以下两种方法创建对象 //Outer out = new Outer(); //Outer.Inner2 inner = out.new Inner2(); //方式1 //Outer.Inner2 inner = new Outer().new Inner2();//方式2 //可以在外部类的方法中创建内部类对象,可以增加数据校验,保证安全性 out.outerMethod(); */ //static--------------------------------------------------------------------- //当使用static修饰成员内部类,可以直接使用外部类名new Outer.innerMethod()的形式创建内部类对象 Outer.Inner inner= new Outer.Inner(); inner.innerMethod(); //当使用static修饰成员内部类,同时成员内部类的方法也用static修饰时,可以直接使用外部类.内部类.方法的形式,调用内部类的方法! Outer.Inner.innerStaticMethod(); } } class Outer { private static int age; static class Inner { public void innerMethod(){ System.out.println("我是内部类的方法,外部类age的值为"+age); } public static void innerStaticMethod(){ System.out.println("我是内部类的方法,外部类age的值为"+age); } } public void outerMethod(){ //数据校验 Inner inner = new Inner(); inner.innerMethod(); } } class Outer2 { private int age2; private class Inner2 { public void innerMethod2(){ System.out.println("我是内部类的方法,外部类age的值为"+age2); } } public void outerMethod2(){ //数据校验 Inner inner2 = new Inner2(); inner2.innerMethod2(); } }
(5)局部内部类
A:带名字的局部内部类
class Outer { //外部类
public void method() { //成员方法
final int a = 10;
class Inner { //成员内部类
public void show() { //成员内部类的方法
System.out.println("show");
System.out.println(a);
}
}
Inner i = new Inner(); //在成员内部类里面创建对象并使用!
i.show();
}
}
B:匿名内部类(掌握)
a:没有名字的内部类。其本质是一个对象。是通过多态来实现的。
b:前提:存在一个抽象类或者接口。
c:格式:
new 抽象类或者接口() {
重写父类方法;
};
本质:是一个继承了类或者实现了接口的子类匿名对象。
例子:
/* 匿名内部类: 在通过简写形式定义一个没有类名的类。 匿名内部类即将匿名定义类与创建对象的动作一起完成。 必须要有实现或者继承关系。 格式: new 类名或者接口名(){覆盖类或者接口中的代码,(也可以自定义内容。)}; //注意使用的是父类或者接口 */ class Demo11 { public static void main(String[] args) { Demo12 demo12 = new Demo12(); demo12.outerMethod(); } } abstract class Animal { public abstract void eat(); } interface MyInterface { public abstract void method(); public abstract void method2(); } class Demo12 { public void outerMethod(){ class Cat extends Animal //内部类 { public void eat(){ System.out.println("舔着吃!"); } } Animal cat = new Cat(); cat.eat(); System.out.println("============================"); Animal anyAnimal = new Animal(){ //没有类名,有对象名 public void eat(){ System.out.println("舔着吃!"); } public void method(){ System.out.println("我是匿名内部类对象的方法"); } }; anyAnimal.eat(); //anyAnimal.method(); new Animal(){ public void eat(){ System.out.println("舔着吃!"); } }.eat(); //===============================以上为抽象类的内部类,以下为接口的内部类 System.out.println("============================"); class MyClass implements MyInterface { public void method() { System.out.println("我是内部类方法1"); } public void method2() { System.out.println("我是内部类方法2"); } } MyInterface mi = new MyClass();//有类名MyClass,有对象名mi mi.method(); mi.method2(); MyInterface mi2 = new MyInterface(){//没有类名,有对象名mi2 public void method() { System.out.println("我是匿名内部类方法1"); } public void method2() { System.out.println("我是匿名内部类方法2"); } }; mi2.method(); mi2.method2(); new MyInterface(){ //没有类名,没有对象名,即匿名对象 public void method() { System.out.println("我是匿名内部类方法1"); } public void method2() { System.out.println("我是匿名内部类方法2"); } }.method(); new MyInterface(){ //没有类名,没有对象名,即匿名对象 public void method() { System.out.println("我是匿名内部类方法1"); } public void method2() { System.out.println("我是匿名内部类方法2"); } }.method2(); } }
d.匿名内部类的使用场景 :
:内部类效率更高。
:通常在使用接口类型参数的方法上,并该接口中的方法不超过三个时,可以将匿名内部类作为参数传递。
:增强阅读性。
例子:
package package3; /* 使用匿名内部类的场景: 1:提高效率 2:当参数类型,返回值类型,成员变量类型为抽象类或者接口时,可以使用匿名内部类。 3:增强阅读性 */ class Demo13 { public static void main(String[] args) { //-----------------普通方式调用 --------------------- Demo13 demo13 = new Demo13(); MyClass mc = new MyClass(); demo13.method(mc); //-----------------创建匿名内部类--------------------- demo13.method(new MyInerface(){ public void method() { System.out.println("匿名对象匿名内部类方法一"); } public void method2() { System.out.println("匿名对象匿名内部类方法二"); } }); MyAbsClass mac = demo13.method2(); mac.eat(); mac.sleep(); mac.hitBeanBean(); } //参数类型为接口的方法 public void method(MyInerface mi) { mi.method(); mi.method2(); } //返回值类型为抽象类的方法 public MyAbsClass method2() { // 方式1:有类名MyClass2、有对象名mac /* MyAbsClass mac = new MyClass2(); return mac; */ //方式2:没有类名,有对象名mac /* MyAbsClass mac = new MyAbsClass(){ public void eat() { System.out.println("匿名内部类中:学完匿名内部类,就吃不下去了!"); } public void sleep(){ System.out.println("匿名内部类中:学完匿名内部类,就睡不着了!"); } }; return mac; */ //方式3:没有类名,没有对象名 return new MyAbsClass(){ //匿名内部类 public void eat() { System.out.println("匿名内部类中:学完匿名内部类,就吃不下去了!"); } public void sleep(){ System.out.println("匿名内部类中:学完匿名内部类,就睡不着了!"); } }; } } //---------------------------接口-------------------------------------- interface MyInerface { public abstract void method(); public abstract void method2(); } class MyClass implements MyInerface { public void method() { System.out.println("方法一"); } public void method2() { System.out.println("方法二"); } } //---------------------------抽象类-------------------------------------- abstract class MyAbsClass { public abstract void eat(); public abstract void sleep(); public void hitBeanBean(){ System.out.println("学完匿名内部类,就开始打豆豆!"); } } //---------------------------非抽象类-------------------------------------- class MyClass2 extends MyAbsClass { public void eat() { System.out.println("学完匿名内部类,就吃不下去了!"); } public void sleep(){ System.out.println("学完匿名内部类,就睡不着了!"); } }
(6)例子:定义并使用内部类。要求包含局部内部类,成员内部类,匿名内部类。
/** * 定义并使用内部类。要求包含局部内部类,成员内部类,匿名内部类。 */ public class Main { public static void main(String[] args) { //调用成员内部类 Fu.Zi zi= new Fu().new Zi(); zi.sleep(); //调用局部内部类 Fu fu=new Fu(); fu.eat(); //调用匿名内部类 fu.method().eatType(); } }
/** * 定义并使用内部类。要求包含局部内部类,成员内部类,匿名内部类。 */ public class Fu { //成员变量 String string = "巴马"; //成员内部类 public class Zi { public void sleep() { System.out.println("睡觉"); } } //局部内部类 public void eat() { class EatMeat extends EatType { //局部内部类,必须要继承抽像类或者继承接口 public void eatType() { System.out.println("吃肉"); } } EatMeat eatMeat = new EatMeat(); eatMeat.eatType(); } //匿名内部类 public EatType method() { //返回值类型或者参数类型为抽象类或者接口 /*EatType type= new EatType(){ public void eatType(){ System.out.println("吃鱼"); } }; return type;*/ return new EatType(){ public void eatType(){ System.out.println("吃鱼"); } }; } }
public abstract class EatType { public abstract void eatType(); }
(7)匿名内部类面试题
/* 匿名内部类练习: Outer.method.show(); 意思为Outer类的静态成员变量method可以调用一个show方法,可以调用show方法的一定是Inter接口的子类实例 Outer.method().show(); 意思为Outer类的静态成员方法method()的返回值可以调用一个show方法,可以调用show方法的一定是Inter接口的子类实例 */ interface Inter{ void show(); } //题目1: class Outer{ //补齐代码 public static Inter method() { //方式1 /* Inter inter = new Inter(){ public void show(){ System.out.println("hello world"); } }; return inter; */ //方式2 return new Inter(){ public void show(){ System.out.println("hello world"); } }; } } class innerClassTest{ public static void main(String[] args){ Outer.method().show(); } } //题目2: /* class Outer{ //补齐代码 public static Inter method = new Inter(){ public void show(){ System.out.println("hello world"); } }; } class innerClassTest{ public static void main(String[] args){ Outer.method.show(); } } */
2:包(掌握)
(1)包就是永远区分相同类在不同文件夹下。其本质就是一个文件夹。
(2)包的作用:让相同类名的类可以存在。为了组织代码。cn.itcast.action cn.itcast.service cn.itcast.db
(3)定义包:
package 包名.包名...;
(4)带包的编译和运行(理解)
A:方式一
手动式
a:javac编译代码
b:手动建立包,把class扔进去
c:java执行,带全路径
B:方式二
自动式
a:通过javac编译自动生成包
javac -d . 文件名
b:通过java运行class文件
java 包名.包名.class文件名不带扩展名
(5)不同包下的类之间的访问。
权限够大才行。
以后,我们所有定义的类都用public修饰。
(6)面试题:
在同一个java文件中,可不可以有多个类?可以。
而我们知道类是可以用public修饰的,那么,可不可以多个类都用public修饰?不可以。
并且,一般的时候,如果有main方法也存在的时候,都是public修饰带main那个类。
文件名必须和该public修饰的类名一致。
(7)实际运行的时候,是要求Class文件在一个文件加下,可以直接调用,如果不在一个文件夹下,导包也是为了导入Class文件。
3:导包(掌握)
(1)如果多次使用一个多级包的类,每次带全路径太麻烦,我们就考虑使用导包。
(2)导包的格式:
import 包名.包名...;
注意:
在同一个包下如果有多个类被使用,可以使用通配符*来导入,但是不建议。
推荐:使用谁导入谁。
(3)面试题:
package,import,class出现的位置?
package > import > class
4:权限修饰符(掌握)
(1)用于保证在不同的情况下可以使用
(2)使用如下
本类 同一个包下 不同包下的子类 不同包下的无关类
private Y
默认 Y Y
protected Y Y Y
public Y Y Y Y
常见的组合规则:
权限修饰符+abstract/final/static+...
我们到底怎么用(开发的时候一般都这么做):
类:
public class Demo { }
成员变量:
变量:private String name; 加上相应的getter和setter
常量:public static final int X = 10;
构造方法:
不让外界创建:private Demo(){}
大部分:public Demo(){}
成员方法:
不让外界用:private void show(){}
大部分:public void method(){}
抽象方法:public abstract void function();