类与对象(二)

  • 代码块

    • 在一对{ }里的代码就是一个代码块。
      { }中的局部变量的作用域只在{ }之内。

    • 代码块分为:普通代码块,构造块,静态代码块和同步代码块

  • 普通代码块定义在普通方法中,直接用{ }定义;
    构造块定义在类中,不加任何修饰符

    • 静态代码块是使用static定义的代码块,静态代码块可以放在主类中,也可以放在除了主类以外的地方。

    我们现在看看各个代码块都是怎样的:

    class A{
    //构造代码块
    public A(){
     System.out.println("A的构造代码块");
       }
    //普通代码块
    {
     System.out.println("A的普通代码块");
    }
    //静态代码块
    static{
     System.out.println("A的第一个静态代码块");
       }
    static{
     System.out.println("A的第二个静态代码块");
       } 
    }
    public class TestDemo extends A {
        public TestDemo(){
           System.out.println("主类的构造代码块");
        }
    {
     System.out.println("主类的普通代码块");
    }
    static{
     System.out.println("主类的静态代码块");
    }
    public static void main(String[] args) {
          new TestDemo();
          new TestDemo();
        }
    }
    

    上段代码的结果为:

    A的第一个静态代码块
    A的第二个静态代码块
    主类的静态代码块
    A的普通代码块
    A的构造代码块
    主类的普通代码块
    主类的构造代码块
    A的普通代码块
    A的构造代码块
    主类的普通代码块
    主类的构造代码块

    由此我们可以看出:由于静态代码块在编译时期就会执行,所以先会执行静态代码块,且静态代码块只会被执行一次执行顺序为谁在前先执行谁,然后是普通的代码块,后面才是构造代码块。每次创建对象都会再次执行它的普通代码块和构造代码块

  • 内部类

    • 内部类就是定义在一个类里面的一个新的类,包含内部类的那个类称为外部类。

    • 内部类的优势
      内部类可以访问外部类的所有数据,包括私有数据
      内部类实现了很好的封装性,它对包中的其他类不可见
      内部类可以实现单继承的缺陷

    • 然而内部类的存在会破坏程序的结构

    我们来看一个简单的例子:

    class Outter{
      private String msg = "Hello World";
      //定义一个内部类
      class Inner{
         public void print(){
         //调用msg属性
         System.out.println(msg);
     }
    }
    //外部类的普通方法
     public void fun(){
     //创建内部类的对象
     Inner inner = new Inner();
     //用内部类的对象调用内部类的方法
     inner.print();
    }
    }
    public class TestDemo1 {
       public static void main(String[] args) {
          //创建外部类的对象
          Outter outter = new Outter();
          //外部类的对象调用外部类的方法
          outter .fun();
    }
    }
    
    • 那么外部类想要访问内部类的属性怎么办:就是先拿到内部类的对象,再用内部类的对象调用内部类的方法。

    • 上面的例子是我们将内部类的对象创建到了外部类的方法中,那么如果在外部类之外怎样创建内部类的对象,我们知道内部类是在外部类里面,所以内部类的创建必须依赖于外部类的实例对象,外部类的实例对象就好比告诉了别人说,嗨,老兄,内部类是我里面的,就是相当于告诉了内部类的作用域,我们来看看在外部类之外到底如何定义的:

             外部类.内部类 内部类对象 = new 外部类().new 内部类();
             例如:Outter.Inner inner = new Outter().new Inner();
      
    • 内部类主要创建在哪呢?

      我们可以根据内部类的创建地方将内部类分为:

      成员内部类:之所以叫成员内部类就是因为它就像类里属性,方法一样是这个类中的成员,只不过这个成员是个类罢了。

      成员内部类里一般情况下不能存在任何static的变量和方法,大哥说,咦,那我要是非要static的变量和方法呢,不得不向大哥低头啊,那就有呗,加上关键字final就可以啦。

      静态内部类:static修饰的内部类就是静态内部类

      静态的内部类人家有static大哥罩着,所以根本不需要依赖你外部类,人家可以直接创建,怎么创建呢:外部类.内部类 = new 外部类.内部类(还是需要外部类说明作用域,有大哥罩着也不太行嘛)。

      静态内部类不可以直接使用外围类的非static成员变量和方法,而非静态的内部类可以。所有的静态的(类、方法、属性等等)都只能直接访问静态的。这是大哥又发话了,我就要访问,好嘞,大哥我把外部类的对象给你,你就可以访问它的非静态数据和方法了。

      class Outter{
            private String msg = "Hello World";
            //定义一个内部类
            static class Inner{
            static final  int a = 1;
            public void print(){
              //调用msg属性
              System.out.println(new Outter().msg);
              System.out.println(this.a);
           }
       }
      

      方法内部类:内部类定义在方法中,也称本地内部类

      1.方法内部类只能在该方法内被使用,出了该方法就会失效,且除了这个方法其他地方是不允许访问的。

      2.方法内部类不允许使用修饰限定符public private protected都不允许

      3.方法内部类想要使用方法形参,该形参必须final声明

      匿名内部类:就是没有名字的内部类

      1.匿名内部类没有访问符修饰
      2.匿名内部类必须继承一个抽象类或一个接口
      3.匿名内部类没有构造方法,因为它没有类名
      4.匿名内部类里不能有静态成员或方法

  • 继承:

    继承就是我继承了我爸爸的所有财产,我爸有两袋米,我就有两袋米,假设我爹还有私有的十袋米,但是我不知道,我就只能显式继承那两袋米,那10袋米并不是我的,就只能隐式继承。

    • 面向对象中的继承也一样,在java中,继承使用extends关键字实现,语法如下:
      class 子类 extends 父类

    • 子类也称为派生类,父类又称基类。

    • 子类继承除构造方法之外的所有属性和方法,只不过私有的只能称得上为隐式继承,子类是直接访问不到的,要访问只能通过setter或getter方法调用。

    • 继承最大的优点就是可以实现代码重用。

      class Animal {
          private String name;
          public Animal(String name){
               this.name = name;
           }
          //这是个通用的方法,实现没有意义,只是告诉其子类去实现它
         public void eat(){
      
           }
      }
      class Dog extends Animal{
               public Dog(String name) {
               //super代表父类对象的引用
                 super(name);
              //对父类方法重写
            }
               public void eat(){
                   System.out.println("啃骨头");
           }
               public void sleep(){
                   System.out.println("睡觉");
          }
      }
       public class TestDemo2 {
            public static void main(String[] args) {
                Animal dog = new Dog("旺财");
                    dog.eat();
                    //强制类型转换
                   ((Dog) dog).sleep() ;
             }
       }
      

      我们可以从上个例子发现:子类可以维持与父类相同的功能,子类也可以进行功能扩充,上面Dog类里面的sleep()方法就是扩充的,当子类继承了父类的属性后必须调用父类的构造方法对父类的属性进行初始化,调用父类构造要用到super关键字,如果super调用无参构造也可以省略不写,如果你没有调用父类构造,系统会自动隐含一个super()语句,如果你的父类里没有无参构造,你就必须指明super()调用的哪个构造方法。

      我们看一个例子:

class Father{
    private String name;
    public Father(){
        System.out.println("我是父类的构造方法");
    }
    //父类的普通方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
class Son extends Father{
    public Son(){
        System.out.println("我是子类的构造方法");
    }
}
public class TestDemo1 {
    public static void main(String[] args) {
        new Son();
    }
}

输出结果为:
我是父类的构造方法
我是子类的构造方法

super()是可以省略的,调用子类的构造方法时会先执行首行隐藏的super()去调用类的构造方法。

  • 继承的缺陷:只能单继承,不允许多继承

  • 但是可以采用多层继承:

        class A{}
        class B extends A{}
        class C extends B{}
    

    这样的继承最多3层。

    • 子类对象的实例化流程:不管如何操作都需要先加载父类
  • 覆写(重写):

    像上面例子中的eat方法就属于方法的重写,只要子类定义了与父类相同的方法或属性就属于重写。

  • 重写方法的特点:方法名相同、参数类型以及个数相同、返回值相同
    要注意的是:重写的方法不能有比父类更加严格的访问权限。

      class A1{
          public void print(){
             System.out.println("A类的print方法");
          }
       }
      class B extends A1{
          public void print(){
             System.out.println("B类的print方法");
           }
      }
      public class TestDemo2{
             public static void main(String[] args) {
                    new B().print();
                }
         }
    

    输出结果为:B类的print方法

    当调用某个方法时,如果该方法已经被子类方法所重写了,那么调用的一定是重写后的方法
    

    属性的重写

    当子类定义了与父类属性名称完全相同的属性时,就成了属性的重写,如果父类的 属性是私有的那就不存在重写了

      class A1{
             public String str = "A";
             public void print(){
                   System.out.println("A类的print方法");
             }
       }
      class B extends A1{
            public String str = "B";
            public void print(){
                   System.out.println("B类的print方法");
           }
       }
      public class TestDemo2{
            public static void main(String[] args) {
                   System.out.println( new B().str );
           }
      }
    

    结果输出为B

    • super关键字也可以调用父类的方法或属性:
      super.方法():调用父类方法
      super.属性:调用父类属性,需要注意父类属性的访问权限

      class A1{
               public String str = "A";
               public void print(){
                    System.out.println("A类的print方法");
              }
      }
      class B extends A1{
             public String str = "B";
             public void print(){
             //super 调用父类方法
              super.print();
              System.out.println("B类的print方法");
             //super调用父类属性,需要考虑父类属性的访问权限
             System.out.println(super.str );
             //this是本类的访问处理操作,this调用时先查找本类,本类没有就调
             //用父类
            System.out.println(this.str );
          }
      }
      public class TestDemo2{
             public static void main(String[] args) {
                  new B().print();
              }
      }
      

      结果为:
      A类的print方法
      B类的print方法
      A
      B

  • final关键字:

    1.final可以修饰类、方法、属性

    2.final修饰的变量就变成了常量,必须在声明时就初始化,并且不能被修改
    final修饰的类不能有子类

    3.一个类被final修饰后,该类的所有方法默认都会加上final修饰

         final class A{}//final修饰类
        
         class A{
               public final void fun();//final修饰方法
          }     
        
         public final int a = 10;//final修饰变量
    
  • 多态

    1.多态性是指同一操作作用于某一类对象,可以有不同的解释,产生不同的执行结果。

    2.多态存在的三个必要条件:需要存在继承和实现关系

    3.需要有重写操作

    4.需要父类引用 引用派生类对象

     比如说上上个例子中的:Animal dog = new Dog("旺财");//基类引用 引用派生类//对象
    

    5.多态的存在提高了程序的扩展性和后期的可维护性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值