第三周 Java语法总结__static关键字__代码块__继承__this和super的区别__重写__final关键字__多态__抽象__接口__形参问题__包__权限修饰符__内部类

文章目录

        • 6.static关键字
            • 1)静态static关键字的特点:
            • 2)关于static关键字的使用注意事项
            • 3)什么时候将变量定义为成员变量:
        • 7.文档说明书:
        • 8.代码块
        • 9.继承
          • 1)继承的概念
          • 2)继承(研究的都是类)的特点
          • 3)继承中使用的注意事项
          • 4)继承中,每一个成员变量的关系问题
        • 10.继承中构造方法的访问
        • 11.this和super 的区别
        • 12.重写
            • 方法重写和方法重载的区别
        • 13.final关键字
        • 14.多态
          • 1.多态的概念
          • 2.多态的前提条件
          • 3.多态的成员访问特点
          • 4.多态的好处
          • 5.多态的弊端
            • 1)解决方案
            • 2)多态的方式:使用向下转型时,可能出现异常
          • 6.孔子装爹
        • 15.抽象
          • 1.抽象类
          • 2.抽象类的特点
          • 3.abstract和哪些关键字冲突
        • 16.接口
          • 1.接口
          • 2.接口的特点
          • 3.接口的子实现类的命名规则
          • 4.接口的成员特点
          • 5.抽象类和接口之间的区别
          • 6.instanceof
        • 17.形参问题
          • 1.形式参数问题的研究:引用类型
          • 2.个方法的返回值是引用类型
        • 18.包
        • 19.权限修饰符
    • 16.内部类
        • 1.格式
        • 2.外部类访问内部类

6.static关键字
1)静态static关键字的特点:
   1)随着类的加载而加载
   2)优先于对象存在:  它不能this共存   (this:代表当期类对象的地址值引用)
               对象还没有new的时候,当前被static修饰的成员就已经内存了
   3)被静态修饰的 可以被多个对象共享:有共享共用的意思
               举例:
                     饮水机中的水(适合)
                     水杯共享(不适合!)
   4)被静态修饰的变量,方法----->静态变量或者静态方法
           我们所说的成员变量和成员方法:都指的是非静态
           静态的成员的访问方式:类名.变量
                                类名.方法名()
//定义一个类
class Demo{
    //定义一个非静态变量
    public int num = 100 ;
    //静态变量
    public static int num2 = 50 ;
    //非静态成员方法
    public void method(){
        System.out.println("method demo...");
    }
    //静态的方法
    public static void function(){
        System.out.println("function demo...");
    }
}

//测试类
public class StaticDemo {
    public static void main(String[] args){
        //访问Demo类中num变量
        Demo d = new Demo() ;
        System.out.println(d.num);
       // System.out.println(d.num2); //以后这种方式不要出现
        //被静态修饰的直接可以通过类名.静态变量名
        System.out.println(Demo.num2);
        System.out.println("---------------------------");
        //访问Demo类中method的方法
        d.method();
       // d.function(); //不推荐这样方法:因为function静态
        Demo.function();
    }
}
2)关于static关键字的使用注意事项
 1)非静态的方法既可以访问静态变量,也可以访问非静态的变量
        既可以调用静态方法,也可以调用非静态方法
 2)静态的方法:只能访问静态变量,
        只能调用静态方法
        简单记:静态只能访问静态
/**
 * 定义一个Person类
 */
class Person{
    String name ;//姓名
    int age ; //年龄
    //String country ;//国籍
    static String country ;//国籍  (类变量:这种变量随着类的加载而加载,优先于对象存在!)
    //提供无参
    public Person(){}
    //提供有参
    public Person(String name,int age,String country){
        this.name  = name ;
        this.age = age ;
        this.country = country ;
    }
    public Person(String name,int age){
        this.name = name ;
        this.age = age ;
    }
    //提供一个show方法显示人的信息
    public void show(){
        System.out.println("当前这个人的姓名是:"+name+",年龄是:"+age+",以及国籍是:"+country);
    }
}

//测试类
public class PersonDemo {
    public static void main(String[] args){

        //创建四个人:古代四大美女
        Person p1 = new Person("西施",25,"中国") ;
        p1.show();
        System.out.println("----------------------------");
       // Person p2 = new Person("貂蝉",26,"中国");
        Person p2 = new Person("貂蝉",26);
        p2.show();
        System.out.println("-----------------------------");
     //   Person p3 = new Person("杨玉环",28,"中国") ;
        Person p3 = new Person("杨玉环",28) ;
        p3.show();
        System.out.println("-----------------------------");
      //  Person p4 = new Person("王昭君",23,"中国") ;
        Person p4 = new Person("王昭君",23) ;
        p4.show();
        //System.out.println(Person.country) ;
    }
}

3)什么时候将变量定义为成员变量:
如果当前这个变量能够描述现实世界事物的属性的时候,这个时候变量就应该定义成员变量,否则局部变量
在开发中,尽量采用局部变量:范围小:方法结束,变量从内存消失
7.文档说明书:
针对某个类,加入一些文档注释
	@author  作者
	@version 代码版本
	@since 后面指定JDK版本号
	以及每一个方法上加入文档注释
	方法中有参数@param 参数名称   对参数进行解释说明的文字
	方法中如果有返回值@return 对返回的结果进行解释说明
	产生文档(document)--html页面
		打开dos控制台
		进入指定目录下:
			javadoc -d  文件夹名称  -author -version  java文件(xxx.java --ArrayTool.java)
//这就针对数组操作的工具类
/**
 * 这个类是针对数组操作的工具类,里面提供了数组的遍历,获取数组中的最大值,以及提供冒泡排序,
 * 以及查询数组中的某个元素的索引值的功能...
 *
 * @author  yang
 * @version  V1.0
 * */
public class ArrayTool {

    //工具类中一般构造方法私有化的:一般是不让外界直接去new(创建实例)
    private ArrayTool(){}

    //printArray是ArrayTool的成员方法

    //这个类中的所有的成员方法加入static
    /**
     * 这个功能是数组的遍历功能,最终遍历的结果形式为[元素1, 元素2, 元素3, ...]
     * @param arr 它是针对指定的数组进行遍历
     * */
    public static  void printArray(int[] arr){//ArrayDemo类的成员方法
        System.out.print("[") ;
        for (int i = 0; i <arr.length ; i++) {
            //判断
            if(i==arr.length-1){
                System.out.println(arr[i] +"]");
            }else{
                System.out.print(arr[i]+", ");
            }
        }
    }

    /***
     * 这个功能是针对数组获取最大值
     * @param arr 在指定的数组中查询
     * @return 最终返回的就是数组中的最大值
     */
    public static int getMax(int[] arr){
        //参照物
        int max = arr[0] ;
        //遍历其他元素
        for(int x = 1 ; x < arr.length ; x ++){
            if(arr[x] > max){
                max = arr[x] ;
            }
        }
        return max ;
    }

    /***
     * 这个功能是针对数组查询数组中某个元素的索引值
     * @param arr  在指定的数组中查询
     * @param key  要查找的指定元素
     * @return    返回结果就是的索引值,如果找不到,则返回-1
     */
    public static int getIndex(int[] arr,int key){
        //假设法
        int index = -1 ;
        for(int x = 0 ; x < arr.length ; x ++){
            if(key == arr[x]) {
                index = x ;
                break ;
            }
        }
        return index ;
    }

    /***
     * 这个功能是针对数据进行冒泡排序,最终数组是一个有序的
     * @param arr 针对指定的数组进行排序
     */
    public static void bubbleSort(int[] arr){
        for(int x = 0 ; x < arr.length-1; x ++){
            for(int y = 0 ; y < arr.length-1 -x ; y ++){
                //判断
                if(arr[y] > arr[y+1]){
                    int temp = arr[y] ;
                    arr[y] = arr[y+1] ;
                    arr[y+1] = temp ;
                }
            }
        }
    }
}
8.代码块
在Java中,使用{}包裹棋起来的内容,成为代码块!
  分类:
     局部代码块 :在方法定义中使用 ,作用:限定局部变量的生命周期
     构造代码块:在类的成员位置(类中,方法外),使用{}包裹起来  作用:给类中的一些成员进行数据初始化
            特点:每次在执行构造方法之前,如果存在构造代码块,先执行构造代码块中的内容!
     静态代码块:
         在类的成员位置,直接使用 static{},特点:随着类的加载而加载,优先于对象存在!
         作用:也可以通过static代码块,对一些操作(后期IO流创建文件/JDBC(Java链接数据库注册驱动))
         静态代码块就加载一次!
     优先级:
    	 静态代码块  >  构造代码块  >  构造方法
//看程序写结果
/*
*   考点:
*   代码块的优先级
*       静态代码块 >构造代码块 > 构造方法
*
*       静态代码块:先执行,而且就执行一次!(因为类就加载一次!)
* */
class Student{
    public Student(){
        System.out.println("Student的无参构造方法");
    }
    {
        System.out.println("Student的构造代码块");
    }
    public Student(String name){
        System.out.println("Student的有参构造方法");
    }
    static{
        System.out.println("Student的静态代码块");
    }
}
public class Test {
    static{
        System.out.println("高圆圆42了,我很伤心");
    }
    public static void main(String[] args) {
        System.out.println("我是main方法");
        Student s = new Student() ;
        Student s2 = new Student("高圆圆") ;
    }
}

/*
高圆圆42了,我很伤心
我是main方法
Student的静态代码块
Student的构造代码块
Student的无参构造方法
Student的构造代码块
Student的有参构造方法
*/
//看程序,写结果
class Root {
    static {
        System.out.println("Root的静态初始化块"); //1)
    }
    {
        System.out.println("Root的普通初始化块"); //4)
    }
    public Root() {
        System.out.println("Root的无参数的构造器");//5)
    }
}
class Mid extends Root {
    static {
        System.out.println("Mid的静态初始化块");//2)
    }
    {
        System.out.println("Mid的普通初始化块");//6)
    }
    public Mid() {
        //super();
        System.out.println("Mid的无参数的构造器");//7)
    }
    public Mid(String msg) {    //"hello"
        this(); //访问的是本类的无参构造方法
        System.out.println("Mid的带参数构造器,其参数值:" + msg);//8)
    }
}
class Leaf extends Mid {
    static {
        System.out.println("Leaf的静态初始化块");//3)
    }
    {
        System.out.println("Leaf的普通初始化块"); //9)
    }
    public Leaf() {
        super("hello"); //显示访问父类的有参构造方法
        System.out.println("Leaf的构造器");//10)
    }
}
public class LeafTest {
    public static void main(String[] args) {
        new Leaf();//匿名对象
    }
}
9.继承
1)继承的概念
将多个类的共性内容抽取到一个独立的类中,然后这多个类和独立的这个类产生一种关系: 继承关系!
     关键字: extends
     class Fu{}
     书写格式 :class Zi extends Fu{}
继承的好处:
      1)提高代码的维护性!
      2)提高代码的复用性!
      3)类和类之间产生的关系,是多态的前提条件
程序开发中:遵循设计原则
      开闭原则
      接口分离原则
      迪米特原则
      依赖注入原则
      ....
 
      这些设计原则都要遵循一个原则 "低(松)耦合,高内聚"(重点)
      实际开发中:耦合避免不了,但是可以降低(类与类之间的关系越少越好!)
               内聚:就是解决某件事件的能力!(一个类的能完成的事情,尽量一个类完成,不要产生过多的关系一块完成!)
                降低耦合性:就可以通过反射(后期:贯穿于整个JavaEE核心技术)来创建某个类的实例!
2)继承(研究的都是类)的特点
1)类与类之间的关系,继承关系,只支持单继承
       格式
           class 子类名 extends 父类名{}
        在有的语言里面,是支持多继承的 (Java中不支持这种写法)
           class 子类名 extends 父类名1,父类名2,..{}
2)虽然不能支持多继承,但是可以支持多层继承!
//多层继承
class GrandFather{
    public void  method(){
        System.out.println("我是爷爷...");
    }
}
class Father extends  GrandFather{
   /* public void  method(){
        System.out.println("我是爷爷...");
    }*/
    public void show(){
        System.out.println("shou Father...");
    }
}
//单继承
class Son extends  Father{
    public void function(){
        System.out.println("function son...");
    }
}
//多继承:类与类之间不支持
//class Son extends  Father ,Mother{

//}
3)继承中使用的注意事项
 1)子类继承父类:可以继承父类的非私有的成员,私有的成员外界不能访问的,只能在本类中访问
      但是可以通过公共方法间接访问!
 2)构造方法是不能被继承的,但是子类可以间接通过 super关键字访问父类的构造方法
4)继承中,每一个成员变量的关系问题
一个类的组成
       成员变量
       构造方法
       成员方法
成员变量
       a)子类继承父类,如果子类中的成员变量名称和父类的成员变量名称不一致,分别访问即可!
       b)子类继承父类,如果子类的成员变量名称和父类的成员变量名称一致:如何访问呢? (重点)
               1)首先在子类的局部位置找,是否存在局部变量名称,如果有,就使用
               2)如果没有,就在子类的成员位置找,是否存在这个变量,如果存在,就使用
               3)如果在子类的成员位置中没有找到,直接在父类的成员位置中找,如果有,就是使用!
               4)如果父类的成员位置都没有,就没有这个变量,报错!
               遵循一个原则:就近原则!
10.继承中构造方法的访问
1)子类继承父类,子类的所有的构造方法都会默认的访问父类的无参方法
        子类的所有构造方法的第一句话:默认隐藏了super() ;  因为子类中肯能会使用到父类的数据,所以在继承关系中
  得先让父类初始化---->构造方法 : 分层初始化!(先父类无参构造方法,在执行子类的构造方法)
         super:代表的父类对象的空间表示(父类对象的地址值引用!)
//父类
class Fu{
  //  private String name ;
   // private int age ;
    //父类的无参构造方法
    public Fu(){
        System.out.println("Fu的无参构造方法...");
    }
    public Fu(String name){
        System.out.println("Fu的有参构造方法...");
    }
}
//子类
class Zi extends  Fu{
    public Zi(){
       // super() ;//隐藏一个关键字super() ; 访问父类的无参构造方法
        System.out.println("Zi的无参构造方法");
    }
    public Zi(String name){
       // super() ;
        System.out.println("Zi的有参构造方法");
    }
}
//测试类
public class ExtendsDemo {
    public static void main(String[] args) {
        //创建子类对象
        Zi zi = new Zi() ;
        System.out.println("------------------------");
        //有参构造创建对象
        Zi zi2 = new Zi("hello") ;
    }
}
/*
Fu的无参构造方法...
Zi的无参构造方法
------------------------
Fu的无参构造方法...
Zi的有参构造方法
*/
2)如果父类中的无参构造方法没有,子类会怎么样?
      子类的所有的构造都会报错! (因为子类所有构造方法默认父类的无参构造方法!)
  如何解决呢?
      方式1:手动给出父类的无参构造方法(推荐)
      方式2:在子类的构造方法中的第一句话:通过super(xxx),间接的访问父类的有参构造方法
      方式3:只要子类的所有构造方法中一个能够让父类初始化即可!
               在子类的构造方法中:this(xxx):---->访问本类的构造方法,然后再子类的构造方法中间接访问父类的有参构造方法super(xxx) ;
//父类
class Father{
    //父类的无参构造方法
   /* public Father(){
        System.out.println("Fu的无参构造方法...");
    }*/

    public Father(String name){
        System.out.println("Fu的有参构造方法...");
    }
}
//子类
class Son extends  Father{
    public Son(){
        super("随便给") ;
        System.out.println("Zi的无参构造方法");
    }
    public Son(String name){
        // super("随便给") ;
        this() ;//访问本类的无参构造方法
        System.out.println("Zi的有参构造方法");
    }
}

//测试类
public class ExtendsDemo2 {
    public static void main(String[] args) {

        Son s = new Son() ;
        Son s2 = new Son("高圆圆") ;
    }
}

/*
Fu的有参构造方法...
Zi的无参构造方法
Fu的有参构造方法...
Zi的无参构造方法
Zi的有参构造方法
*/
11.this和super 的区别
总结:this和super 的区别
     this:代表的当前类对象的地址值引用
     super:代表的父类对象的地址值引用(代表父类的空间标识)
 
     访问成员变量
          this.变量名; 访问的本类中的成员变量
          super.变量名; 访问的是父类的成员变量
 
     访问构造方法:
          this() ; 访问本类的无参构造方法
          super() ;访问的父类的无参构造方法
 
          this(xxx);访问的本类的有参构造方法
          super(xxx);访问的父类的有参构造方法
          
     成员方法:
          this.方法名();访问的是本类的成员方法
          super.方法名() ;访问的是父类的成员方法
12.重写
重写:如果子类出现了和父类一模一样的方法声明,叫做方法重写!(Override) ---方法复写(覆盖)
重写的目的:子类有自己的功能,需要将父类的该功能覆盖掉!

重写权限

	当前子类继承父类的时候,如果存在方法重写,那么子类重写父类该方法访问权限不能更低!
要么跟父类的方法保持一直,要么带上public(推荐跟父类的方法一直即可!)
//定义一个手机类 :Phone
class Phone{
    //打电话
    public void call(){
        System.out.println("手机可以打电话...");
    }
}
//新的手机类
class NewPhone extends  Phone{

    //子类出现了和父类一模一样的方法声明:沿用打电话的功能,并且还需要提供新的功能
    //@Override  :标记当前这个方法是重写父类的方法 (JDK提供的内置注解)
    public void call(){

        System.out.println("可以看天气预报了...") ;
        //沿用父类的功能
        super.call();

        System.out.println("还可以听音乐...") ;
    }
}
//测试类
public class ExtendsDemo2 {
    public static void main(String[] args) {
            //创建子类对象
        NewPhone np = new NewPhone() ;
        np.call();
    }
}
方法重写和方法重载的区别
面试题:
   方法重写和方法重载的区别?
       方法重载:   在一个类中,提供n多个功能,这些功能,方法名相同,参数列表不同,与返回值无关(目的:提高某个功能的扩展性)
                        参数列表不同:
                                1)类型不同
                                2)个数不同
                                3)考虑参数类型的顺序
 										public static void open(int a,double d){}
                                        public static void open(double a,int b){}
                   					构造方法也可以重载!
 
       方法重写:
                   在继承关系中,子类出现了父类一模一样的方法声明,重写的目的:子类有自己的功能,需要将父类的该功能覆盖掉!
                          举例:
                                   动物:
                                           都具备吃和睡的功能
                                         猫和狗都继承自动物类,他们吃的不一样的
                                         猫和狗就需要讲吃和睡的功能覆盖掉...
                                               猫具体吃鱼
                                               狗具体吃肉
13.final关键字
final(状态修饰符):最终的,无法更改的
   关于final关键字的特点:
       1)可以修饰类,该类不能被继承!
       2)可以修饰符成员方法,成员方法不能重写!  (根据具体的题意要求!)
       3)可以修饰的变量,这个变量此时是一个常量! (自定义常量)
class Fu2{
    public  int num = 20 ;
    public  final int num2 = 30;  //就是 不能更改的变量: 值永远是30 (自定义常量)
    public final void method(){
        System.out.println("method Fu2...");
    }
}
//定义一个子类
class Zi2 extends  Fu2{
    /*public void method(){
        System.out.println("method Zi2...");
    }*/

    //子类自己的功能
    public void show(){
        final int num3  ; //被final修饰的局部变量:可以先定义,但是必须在使用前初始化,只能赋值一次
        num3 = 40 ;
        System.out.println(num3);

       // num3 = 50 ;
    }
}


//测试类
public class FinalDemo2 {
    public static void main(String[] args) {
        //创建子类对象
        Zi2 zi2 = new Zi2() ;
        zi2.method();
        System.out.println("--------------------");
        zi2.num = 100 ;
        System.out.println(zi2.num);
        //zi2.num2 = 50 ; //被final修饰的变量,只能赋值一次,不能再次赋值!
        System.out.println(zi2.num2);

        zi2.show();

    }
面试题:
   final ,finally,finalize()的区别?
   		final的关键字描述以及的三个特点
 		finally:处理异常用到 try...catch...finally(后面讲)
        finalize():跟垃圾回收器有关系:回收内存中没有更多引用的对象(后面在讲常用类使用以下)
final修饰变量,此时变量是一个常量
     变量:普通变量
             final int a = 10 ;
          实例变量
             final Student s = new Student() ;
final修饰基本数据类型和引用类型的区别?
       final修饰基本数据类型: 基本数据类型的对应的数据值不能在被赋值了,只能赋值一次!
       final修饰引用类型:引用数据类型对应的地址值不能被改变
             final Student s = new Student() ;//修饰实例变量s,s的堆内存地址值永远是固定值!
                      s = new Student() ;//重新开辟空间(报错)
 开发中书写常量:
        都使用public static final int a = 100 ;
        public:访问权限足够大
        static:可以被类名直接访问
        final:这个变量是一个常量

        class Constant{
       	 	 public static final int a = 100 ;  //自定义常量
       		 public static final Student s = new Student() ;
       		 //成员位置定义的:静态实例变量
        }
        Constant.a:类名.变量名;
14.多态
1.多态的概念
多态:一个事物在不同时刻不同形态
       举例:
              现实世界事物 :水
                     气态,固态,液态
 
               程序世界:
                      在内存中的变化
                      猫是动物 Animal a = new Cat() ;
                      猫是猫: Cat c = new Cat() ;
2.多态的前提条件
     1)必须存在继承关系 (extends)
     2)必须存在方法重写
              子类需要覆盖父类的功能
                     Animal
                             eat():"动物都需要吃饭..."
                     Cat
                             eat() "猫吃鱼"
                     Dog
                             eat() "狗吃骨头"
     3)必须有父类引用指向子类对象
            class Fu{}
            class Zi extends Fu{
                   //存在重写
            }
               格式: Fu fu = new Zi() ;

3.多态的成员访问特点
       Fu fu  = new Zi() ;
       1)针对成员变量的访问问题:
                编译看左,运行看左!(使用父亲的东西)
       2)针对多态中的成员方法的访问问题:  我们所说的成员变量/成员方法----非static
                编译看左,运行看右(因为子类重写了父类的东西)
       3)如果成员方法是静态方法:(静态成员方法 算不上方法重写,直接可以类名来访问,跟类相关的方法)
               编译看左,运行看左
       4)构造方法:
                存在继承关系: 还需要让父类先构造初始化,然后再子类进行构造初始化!(分层初始化!)
//动物类
class Animal{
    int age = 10 ;
    public void eat(){
        System.out.println("动物饿了就需要吃饭...");
    }
    public Animal(){
        System.out.println("Animal的无参构造方法");
    }

    //父类的静态show
    public static void show(){
        System.out.println("show animal...");
    }
}
//猫类
class Cat extends  Animal{
    int age = 3 ;
    public Cat(){
        System.out.println("Cat无参构造方法");
    }
    public void eat() {//猫吃鱼
        System.out.println("猫吃鱼");
    }
    //子类的静态show
    public static void show(){
        System.out.println("show Cat...");
    }
}
//测试类
public class DuoTaiDemo {
    public static void main(String[] args) {
        //使用多态来进行测试
        //父类引用指向子类对象
//        格式: Fu fu = new Zi() ;
        Animal a  = new Cat() ;
        System.out.println(a.age);
        a.eat();
//        a.show() ;//静态方法当然推荐这种访问
       // Animal.show();
        //Cat.show();
    }
}
4.多态的好处
   1)提高代码的复用性:由继承保证
   2)提高了代码的扩展性:由多态保证 (重点)
     	Fu fu = new Zi() ; 父类引用可以指向子类对象
//有一个动物类
class Animal2{
    //吃和睡
    public void eat(){
        System.out.println("动物饿了,都需要吃饭...");
    }
    public void sleep(){
        System.out.println("动物困了,都需要休息...");
    }
}

//两个子类
class Cat2 extends  Animal2{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }

    @Override
    public void sleep() {
        System.out.println("猫趴着睡觉");
    }
}
class Dog2 extends  Animal2{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }

    @Override
    public void sleep() {
        System.out.println("狗侧着睡觉");
    }
}
//定义一个动物类的工具类:AnimalTool
class AnimalTool{

    //构造方法私有:不让外界new
    private AnimalTool(){}
   //父类引用可以指向子类对象:形式参数就可以传递Animal2
    public static void createAnimal(Animal2 a){ //    Animal2 a =  new Dog2();
        a.eat(); //多态的成员方法访问问题
        a.sleep();
    }
}

//测试类
public class DuoTaiDemo2 {
    public static void main(String[] args) {
        //具体的动物类创建对象
        //喜欢狗--创建一只狗
        Dog2 d = new Dog2() ;
        d.eat();
        d.sleep();
        //创建第二只
        Dog2 dd = new Dog2();
        dd.eat();
        dd.sleep();
        System.out.println("----------------------");
        //创建猫
        Cat2 c = new Cat2() ;
        c.eat();
        c.sleep();
        //第二只猫
        Cat2 cc = new Cat2() ;
        cc.eat();
        cc.sleep();
        System.out.println("=============================================");

        //上面的问题:随着类型的增加(猴子,猪,大象...),不但提供的对应类型还需要通过createXXX(XXX 类型)
        //继续优化:单独定义一个动物类的工具类AnimalTool(构造方法私有化,提供对外的静态功能)
       // AnimalTool.createDog(new Dog2());
        //AnimalTool.createCat(new Cat2());

        //代码:只是将两个功能封装到一个工具类AnimalTool中,随着动物类型不断增加,createXXX()不断增加
        //形式参数传递的是一个父类,父类引用指向子类对象
        AnimalTool.createAnimal(new Dog2()); //Animal2 a = new Dog2() ;
        AnimalTool.createAnimal(new Cat2()); //Animal2 a = new Cat2() ;
    }
}
5.多态的弊端
     不能访问子类的特有功能   (Fu f = new Zi())
            f.方法名() ;报错了. 父类中没有子类特有功能!
class Father{
    public void show(){
        System.out.println("show father...");
    }
}
//子类
class Son extends  Father{
    public void show(){
        System.out.println("show son...");
    }

    //特有功能:
    public void playGame(String gameName){
        System.out.println("会玩"+gameName+"游戏");
    }
}
//测试类
public class DuoTaiDemo3 {
    public static void main(String[] args) {
        //父类引用指向子类对象:向上转型
        Father father = new Son() ;
        father.show();
        //father.playGame() ; //编译都报错了: 父类中没有玩游戏的功能 ,玩游戏属于Son类的特有功能
        System.out.println("-------------------------");

    }
}
1)解决方案
方案1: (不推荐)
	具体的子类创建具体的子类对象  Zi z = new Zi() ;
	z.成员方法名() ;
	本身Fu f = new Zi() ;已经在堆内存中开辟空间了
	Zi z = new Zi() ;在堆内存中又开辟空间,从内存角度考虑,这种比较消耗内存空间,不太好!

方案2:(推荐使用:"向下转型")
	多态的第三个前提条件:父类 引用指向子类对象      :"向上转型 "Fu f = new Zi() ;
	能不能将父类的引用转换成子类的引用?   好处:不需要在堆内存开辟空间
	可以------>"向下转型"
	Zi z =   (Zi)f ;  还原成子类型

	强转类型转换: 目标类型 变量名 =(目标类型)初始化值;
//父类
class Father2{
    public void show(){
        System.out.println("show father...");
    }
}
//子类
class Son2 extends  Father2{
    public void show(){
        System.out.println("show son...");
    }

    //特有功能:
    public void playGame(String gameName){
        System.out.println("会玩"+gameName+"游戏");
    }
}
//测试类
public class DuoTaiDemo4 {
    public static void main(String[] args) {
        //父类指向子类对象
        Father2 father2 = new Son2() ;
        father2.show(); //编译看左,运行看右,存在重写

        //father2.playGame( "lol");//父类没有方法
        System.out.println("------------------------------");

        //方案1:创建具体的子类对象
        Son2 son2 = new Son2() ;
        son2.playGame("lol");

        System.out.println("------------------------------");
        /**
         * "向下转型"
         *                            Zi z =   (Zi)f ;  还原成子类型
         */

        Son2 s = (Son2) father2;
        s.playGame("csgo");
    }
2)多态的方式:使用向下转型时,可能出现异常
         要使用向下转型,前提必须有父类引用指向子类对象 Fu f = new Zi() ;
         遵循向下转型的格式:
                    Zi z = (Zi)f;     必须心里清楚堆内存存储的类型....
     向下转型使用不当,就出现java.lang.ClassCastException:类转换异常: (属于运行时期异常)
         当前堆内存中的实例不是该类型时,就会出现问题!
//定义一个动物类
class Animal{
    public void eat(){
        System.out.println("动物都需要吃饭");
    }
}
//狗类
class Dog extends  Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
}
//猫类
class Cat extends  Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

//测试类
public class DuoTaiDemo {
    public static void main(String[] args) {
        //多态版测试猫
        Animal a = new Cat()  ;//此时 堆内存是猫       (猫是动物)
        Cat c = (Cat) a ;  //还原成猫类型  :猫是猫
        a = new Dog() ; //此时:堆内存是狗   (狗是动物)
        Dog d = (Dog)a; //还原成狗的类型: 狗是狗
        Cat cc = (Cat)a ;//现在没有报错:语法正确的:符合强转类型语法格式,运行出错java.lang.ClassCastException:类转换异常
    }
}
6.孔子装爹

第三周 Java语法总结__static关键字__代码块__继承__this和super的区别__重写__final关键字__多态__抽象__接口__形参问题__包__权限修饰符__内部类_第1张图片

15.抽象
1.抽象类
什么是抽象类----->现实世界事物中,某个事物是比较概括性(人/水果/动物),描述为抽象事物
将一些公共性内容抽取到独立的类中,并且有些功能仅仅给出声明,不具体实现,具体实现通过子类进行,
	
 	只有具体的工人/苹果/猫或者狗,才具备具体的功能;
 	将某个事物中的一些功能仅仅给出声明即可,没有方法体----->抽象方法---->此时这个类必须为抽象类!
举例:
    动物都需要吃和睡
    只要看到具体的动物类:猫类/狗类,才具备吃和睡的功能
    将动物类中的吃和睡给出一个声明:加入一个关键字 abstract:抽象方法
    动物类----->抽象类*    
抽象的关键字:Java语言 :abstract关键字 (抽象的含义)

抽象方法的格式;
    权限修饰符(一般情况都是public) abstract 返回值类型  方法名(形式参数列表) ;

抽象类的格式:
    abstract  class 类名{}
2.抽象类的特点
1)有抽象方法的类一定是抽象类
2)抽象类中不一定只有抽象方法 ,还可以非抽象方法(有方法体)
3)抽象类不能实例化---->意思:不能创建对象
	如何实例化呢:通过具体的子类进行实例化(进行对象的创建), 抽象类多态  Fu fu = new Zi() ;Fu类型 抽象类型
4)抽象类的子类有两种情况:
	1)目前来说:如果抽象类的子类都是抽象类---毫无意义  因为子类也不能new ,除非再有具体的子类
	2)抽象类的子类具体类---才能new     :抽象多态的形式  Fu fu = new Zi() ;
抽象类的核心宗旨:就是强制子类必须完成的事情(要将父类中的所有的抽象方法必须重写,否则报错!)
抽象类成员特点:
	成员变量
           既可以定义变量,也可以常量:被final修饰
    成员方法
           既可以定义为抽象方法,也可以定义为非抽象方法
 
           如果定义为抽象方法:关键字abstract(显示给出)
    构造方法
           存在无参构造/有参构造方法---->目的:分层初始化
//定义一个动物类
abstract class Animal{
    /*public void eat(){
        System.out.println("动物都需要吃饭");
    }*/
    public  abstract void eat(); //加入关键字abstract
    public void  show(){//具体方法
        System.out.println("show animal...");
    }
    public abstract  void slepp() ;//睡
    public Animal(){ //Animal抽象类=---- 不能new Animal()
        System.out.println("Animal的无参构造方法");
    }
}
//子类
//目前来说:如果抽象类的子类都是抽象类---毫无意义  因为子类也不能new ,除非再有具体的子类
//abstract class Cat extends Animal{
//具体类
 class Cat extends Animal{

    public Cat(){
        System.out.println("Cat的无参构造方法");
    }
    @Override
    public void eat() {
        System.out.println("猫吃鱼...");
    }
    @Override
    public void slepp() {
        System.out.println("猫趴着睡觉...");
    }
    //特有功能
    public void playGame(){
        System.out.println("猫玩毛线");
    }
}
class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
    @Override
    public void slepp() {
        System.out.println("狗侧着睡觉...");
    }
    //特有功能
    public void catchRabit(){
        System.out.println("狗可以抓兔子");
    }
}
//测试类
public class AbstractDemo {
    public static void main(String[] args) {
        //创建动物类对象
        //类名 对象名 = new 类名() ;
       // Animal a = new Animal()  ;//不能创建对象,如何实例化呢?
        //使用多态的形式: 当前的Animal类的子类一定是具体类
        Animal a = new Cat() ;//父类引用指向子类对象(父类---抽象类) : 抽象类多态
        a.eat();
        a.slepp();
       // a.playGame() ; 父类没有这个功能
        //向下转型
        Cat c = (Cat)a ;
        c.playGame();
        System.out.println("-------------------------");

        a = new Dog() ;
        a.eat();
        a.slepp();

        Dog d = (Dog) a;
        d.catchRabit();
    }
}
面试题:
   一个类中没有抽象方法,那么将这个类定义为抽象类的意义何在?
       意义:为了不让它直接实例化!
       如何实例化:
               情况1)直接就有具体的子类
               情况2)间接的有具体的子类
 
            可能:某个功能的返回值是它本身----->功能里面的逻辑可能就是在new  最具体的子类!
3.abstract和哪些关键字冲突
1)private冲突:
	私有的方法,只能在本类中访问,加入abstract目的需要被子类重写,需要调用子类的功能!
2)static冲突:
	静态方法随着类的加载而加载,而静态方法---算不上重写,所以它的访问
	通过类名.方法名()---->而抽象方法没有方法体
3)final冲突
	被final修饰的成员方法是不能被重写的,而加入abstract的方法需要被重写的!
 
abstract能够跟的关键字
 	public
 	默认修饰符
 	protected:受保护的 (范围:同一个包下的当前类或者子类中或者不包下的子类)
 
abstract一般在类上使用---->抽象类
在方法上使用---->抽象方法
可以在接口中使用
16.接口
1.接口
  接口---->它的本质就是体现一个现实世界事物所具有的的额外的扩展功能!
  定义格式:    interface  接口名{}  ------>接口名遵循"标识符规则"---->大驼峰命名法
  接口中的方法:不能有方法体,隐藏public abstract关键字,只能是抽象方法,不能有方法体
2.接口的特点
1)不能实例化(不能创建对象)
2)如何实例化
     接口实例化: 通过接口的子实现类(一定是具体类)进行实例化----接口多态(使用时最多的!)
     子实现类和接口的关系: implements 实现关系
     接口的子实现类如果是抽象类----->肯定要存在抽象类的具体的子类,否则都不能实例化!
3.接口的子实现类的命名规则
开发中--->在接口名的后面+Impl:子实现类
       interface Inter{}
       class InterImpl  implements Inter{
       }
//定义一个接口:
interface  Jump{ //跳高接口
   public abstract  void jump() ;
}

//定义一个跳高猫类
class JumpCat implements Jump{ //实现关系--->关键字:implements
    @Override
    public void jump() {
        System.out.println("猫可以跳高了...");
    }
}
//测试类
public class InterfaceDemo {
    public static void main(String[] args) {
	//创建接口对象
        //Jump jump = new Jump() ;//不能实例化
        //接口多态:----- 之前抽象类多态:Fu fu = new Zi() ; Fu类抽象类
        //接口--->指向子类实现类对象
        Jump jump = new JumpCat() ;
        jump.jump(); //编译看左,运行看右!(接口只能有抽象方法)
    }
}
4.接口的成员特点
1)接口中的成员方法: 只能是抽象方法,默认的修饰符:public abstract(可以省略不写)
2)接口没有构造方法
3)接口的成员变量只能是常量: 存在默认修饰符:public static final (可以省略不写)
5.抽象类和接口之间的区别
1)成员的区别:
	抽象类中
        成员变量:既可以是常量,也可以是变量
        成员方法:既可以是抽象方法(abstract不能省略),也可以是非抽象方法
        构造方法:既存在无参构造方法,也可以存在有参构造方法(目的:为了给当前类进行数据初始化)
                    abstract class Animal{
                            private String name ;
                            private int age ;
                            private String color ;
                            public Animal(){}
                            pbblic Animal(String name,int age,String color){
                                this.name = name ;
                                this.age = age ;
                                this.color = color ;
                            }
                            public abstract void eat() ;
                    }
                    class Cat extends Animal{
                            public Cat(){
                            }
                            public Cat(String name,int age,String color){
                                super(name,age,color) ;
                            }
                            public void eat(){
                                    //...
                            }
                    }
                    Animal a = new Cat() ; //抽象类多态
	接口中
		成员变量:只能是常量,存在默认的 修饰符 public static final (可以省略不写)
		成员方法:只能是抽象方法:存在默认修饰符 public abstract(省略不写)
		构造方法:没有构造方法,接口中所有的方法---都认为是没有方法体

2)关系的区别
	三点
		类与类之间的关系: extends 继承关系
                       只支持单继承,不支持多继承,但是可以多层继承

		类和接口的关系:   implements关系:实现关系
                       个类继承另一个类的同时,可以实现多个接口,中间逗号给隔开
                       
		接口与接口之间:   extends:继承关系
                       不仅支持单继承,也可以多继承,中间使用逗号隔开
3)设计理念的区别
	抽象类--->不能实例化---通过具体的子类实例化---->存在继承关系,体现的是一种 "is a"的关系
	接口---->不能实例化--->通过具体的子实现类实例化---->谁如果实现了接口,就具备额外的功能,体现的是一种"like a"的关系
6.instanceof
instanceof:提供操作符号(二元(二目)操作符号:) 最终true/false
           ==
           >=
           <=
           >
           <
      对象  instanceof 引用类型
      描述左边的对象是否是当前右边的类型的实例        (实例---->对象)
abstract  class Animal{
    public Animal() {
    }
    public abstract  void eat() ;
}
class Dog extends  Animal{
    public Dog() {
    }
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }
}
class Cat extends  Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
class Pig extends  Animal{
    @Override
    public void eat() {
        System.out.println("猪吃白菜...");
    }
}
//测试类
public class Test3 {
    public static void main(String[] args) {
            Animal a = new Dog() ;
            a = new Pig() ;
            //if语句
            if(a instanceof  Dog){
                System.out.println("是狗类型的实例");
            }else if(a instanceof Cat){
                System.out.println("是猫类型的实例");
            }else if(a instanceof  Pig){
                System.out.println("是猪类型的实例");
            }else{
                System.out.println("对不起,没有当前实例...");
            }
    }
}
17.形参问题
1.形式参数问题的研究:引用类型
形式参数问题的研究:引用类型
   如果方法的形式参数是类    调用方法的时候,如何传递实际参数?
          具体类 :调用该方法,实际参数需要传递当前具体类的对象
          抽象类 :调用该方法实际参数需要传递的抽象类的子类对象 (抽象类多态)
 	      接口 : 调用该方式,实际参数需要传递的是当前接口的子实现类对象(接口多态)
//定义一个接口
interface Love{
    void love() ;
}
//LoveDemo类
class LoveDemo {                        //Love love = new LovePerson() p
    public void function(Love l){//方法的形式参数是接口类型,必须传递接口的子实现类对象
        l.love();//love.love() ;
    }
}
//定义一个接口的子实现类
class LovePerson implements  Love{
    @Override
    public void love() {
        System.out.println("爱生活,爱Java,爱高圆圆...");
    }
}
//测试类
public class LoveTest {
    public static void main(String[] args) {
        //需要访问LoveDemo类中的function方法
        //创建LoveDemo类对象
        LoveDemo ld = new LoveDemo() ;
        //Love love  = new Love() ; //接口不能实例化
        //接口多态
        Love love = new LovePerson() ;
        ld.function(love) ;
        System.out.println("------------------------");

        //匿名对象
        new LoveDemo().function(new LovePerson());
    }
}
2.个方法的返回值是引用类型
如果一个方法的返回值是引用类型,最终方法结束,如何返回?
     具体类  :方法返回的就是当前具体类对象!
     抽象类 :需要返回的是抽象类的子类对象
 	 接口:需要返回的是该接口的子实现类对象

1)具体类

class Student{
    public void study(){
        System.out.println("Good Good Study,Day Day Up!");
    }
}
//StudentDemo类
class StudentDemo {
    public Student show() { //方法的返回值是引用类型---具体类 :需要返回的当前类的具体对象
        return new Student();
    }
}
//测试类
public class StudentTest {
    public static void main(String[] args) {
        //调用StudentDemo类中的show方法?
        //创建StudentDemo类对象
        StudentDemo sd = new StudentDemo() ;
        Student s = sd.show(); //Student s = new Student();  sd.show()---->返回的具体的学生对象
        s.study();
        System.out.println("-----------------------");
        //匿名对象
        Student student = new StudentDemo().show();
        student.study();
    }
}

2)抽象方法

abstract class Person{
    public  abstract void work() ;
}

//定义一个子类 继承Person类
class Worker extends  Person{
    @Override
    public void work() {
        System.out.println("工人不断的去工作...");
    }
}

//PersonDemo类
class PersonDemo{
    public Person method(){ //返回值类型是一个引用类型---抽象类的情况,需要返回的是抽象类的子类对象
       // Person p = new Worker() ;
        //return p ;
        //一步走
        //匿名对象
        return new  Worker() ;
    }
}

//测试类
public class PersonTest {
    public static void main(String[] args) {
        //需要调用PersonDemo类中的method 方法?
        PersonDemo pd = new PersonDemo() ;
        Person person = pd.method(); // method方法其完成了一件事件: Person person  = new Worker() ;
        person.work() ;
        System.out.println("---------------------------------");
        //匿名对象
        Person p = new PersonDemo().method();
        p.work() ;
    }
}

3)接口

//定义一个接口
//结婚的接口
interface  Mary{
    public abstract  void mary() ;
}

//定义一个类
class You implements  Mary{
    @Override
    public void mary() {
        System.out.println("结婚了,很开心...");
    }
}

//MaryDemo类
class MaryDemo{
    public Mary function(){//返回值类型是接口类型,
        //需要提供接口的子实现类对象
        //接口多态
       // Mary mary = new You() ;
       // return mary ;
        //一步走
        return new You() ;
    }
}

//测试类
public class LoveTest {
    public static void main(String[] args) {
        //调用MaryDemo类中的function方法?
        MaryDemo maryDemo = new MaryDemo() ;
        Mary mary = maryDemo.function();
        mary.mary();
        System.out.println("----------------------");
        //匿名对象
        Mary m = new MaryDemo().function();
        m.mary();
    }
}
18.包
包:关键字 package
       包的真实含义:
               以后要代码分层...
               将包进行划分
           开发中,写包名的时候(字母都是小写,多级包) :公司域名反写
           开发中:
                   先按照模块划分,在按照功能划分
                           用户模块
                                   注册功能
                                   登录功能
                                   用户激活功能(使用邮件激活技术,手机短信验证,微信二维码)
                                   用户退出
                           商品模块
                           订单模块
                           购物车模块
                           支付模块
               举例:
                           com.qf.pojo/entity/domain  : 存储实体类
                               com
                                   qf
                                       pojo
                                       存储实体类----能够描述现实世界事物
                                       User类                                                   用户
                                       name,password,birthday,sex,email                          属性:姓名,密码,出生日期,性别,邮箱
                                       商品实体                                                  商品
                                        Product                                                  属性:商品名称,商城价格,市场价格上架日期,
                                        pname,shop_price,market_price,pdesc,pdate,....
 
                   开发中:
                               com.qf.dao :   数据库访问层
                                   com
                                          qf
                                               dao
                                                       UserDao: 用户数据库持久层  (针对用户数据库访问接口层---->JDBC(Java连接数据库))
                                                                  两个功能:注册/登录功能
                                                                  public abstract boolean isLogin(User user) ;
                                                                  public abstract boolean register(User user) ;
                               com.qf.dao.impl(针对用户数据库访问接口实现层)
                                                    UserDaoImpl  implements UserDao
 
                                                                   重写isLogin(User user)和register(User user)功能
                           业务层代码:
                                   com.qf.service :
                                               UserService:针对用户的业务接口层
                                                   登录/注册的业务
 
                                   com.qf.service.impl:针对用户的业务接口实现层
                                               UserServiceImpl implements UserService
                                                     注册:
                                                           判断用户名和密码在数据库中是存在,如果存在,
                                                           就不能在注册了;如果不存在,可以进行注册
                                                      登录:
                                                           首先通过用户名先找到用户User----如果找到User
                                                           继续判断 User里面的密码是否和前台输入的密码是否一致,
                                                           如果一致,登录成功,
                                                           否则,错误信息提示....
                        控制层:  控制业务层数据--->进行页面的渲染(视图):jsp,freemarker:网页静态化.... (模板引擎)
                               com.qf.controller:
                                               UserController :
                                                       调用UserService层:获取业务层数据
 
                                                       通过后期:请求转发/重定向技术---进行页面跳转   (后期:开源框架:springmvc:视图解析器)
19.权限修饰符
同一个包下的当前类中 同一个包下的子类/无关类中 不同包下的子类中 不同包下的无关类中
private
默认
protected
public
修饰的权限从小到:private,默认,protected,public

16.内部类

1.格式
内部类:
    在一个类中可以定义另一个:
    在类A 中定义了类B,将类B就称为类A的内部类,类A就是外部类!
成员内部类:
    在一个类的成员位置中定义了另一个类
    内部类可以访问外部类的成员,包括私有!
//外部类
class Outer{
    //成员变量
    public int num = 100 ;
    private int num2 = 200 ;
    class Inner{ //成员内部类
        //成员内部类的一个成员方法
        public void method(){
            System.out.println("method Inner");
            System.out.println();
            System.out.println(num2);
        }
    }
    //外部类的成员方法
    public void show(){
        //访问的成员内部类的method--->通过创建内部类对象来访问
        //method() ;错误的----访问的本类的method方法
        Inner inner = new Inner() ;
        inner.method();
    }
}
//测试
public class InnerClassDemo {
    public static void main(String[] args) {
        //创建外部类对象
        Outer outer = new Outer() ;
        outer.show();
    }
}
2.外部类访问内部类
1)外部类如何直接访问内部类的成员方法?
     格式:
            外部类名.内部类名  对象名 =  new 外部类对象().new 内部类对象() ;
class Outer2{
    private int num = 20 ;
    //成员内部类
    class Inner2{
        public void show(){
            System.out.println(num);
        }
    }
    //外部类的成员方法
    public void method(){
        // 创建内部类对象访问内部类的成员方法
    }
}
//测试类
public class InnerClassDemo2 {
    public static void main(String[] args) {
        //外部类名.内部类名  对象名 =  外部类对象.内部类对象;
        //适用于:通过外部类直接访问成员内部类的成员(前提条件:当前成员内部类是一个非静态类)
        Outer2.Inner2 oi = new Outer2().new Inner2() ;
        oi.show() ;
    }
}
2)关于我们成员内部类的修饰符:
           在成员内部类上面---加入private修饰:为了数据的安全性,它的访问---就要外部类的公共访问间接访问...
伪代码
     举例:
     人首先身体---身体内有心脏
           class Body{
               //内部类:心脏
             private  class Heart{  //加入private:保证数据的安全性
                      //手术
                    public void operator(){
                        System.out.println("心脏搭桥手术....") ;
                    }
               }
               //外部类提供一些公共访问
               public void method(){
                  if("如果你是外科医生"){
                       Heart heart = new Heart() ;
                       heart.operator() ;
                   }
               }
           }
           //外部类直接访问成员内部类的成员
3)如果当前成员内部类是静态的,  里面的方法无论是静态的还是非静态的,都只能访问外部类的静态成员,包括私有!
  如何直接访问静态成员内部类的成员呢?
       将静态的成员内部类看成是外部类的静态成员访问
       直接访问方式
               外部类名.内部类名 对象名 = new 外部类名.内部类名() ;
class Outer3{
    //定义非静态的成员变量
    public int num = 50 ;
    private static int num2 = 20 ;
    //定义成员内部类:静态的           ---->静态的成员内部类可以看成是外部类的静态成员
    static class Inner3{//此时类都是静态
        public void show(){
           // System.out.println(num);
            System.out.println(num2);
        }
        public static void show2(){
           // System.out.println(num);
            System.out.println(num2);
        }
    }
}
//测试类
public class InnerClassDemo3 {
    public static void main(String[] args) {
        // 外部类名.内部类名 对象名  = 外部类对象.内部类对象;
        //Outer3.Inner3 oi = new Outer3().new Inner3() ;  适用不了了
        //   外部类名.内部类名 对象名 = new 外部类名.内部类名() ;
        Outer3.Inner3 oi = new Outer3.Inner3() ;
        oi.show();
        oi.show2() ; //静态---不推荐对象名访问
        System.out.println("------------------------------");
        //show2()的另一种方式
        Outer3.Inner3.show2(); //show2()静态方法
    }
}

你可能感兴趣的:(java语言基础,java)