JAVA学习日记(十)修饰符+权限修饰符+抽象类/方法+代码块+接口+内部类

二十、包

包就是文件夹,用来管理各种不同功能的Java类,方便后期代码维护。

包名的规则:公司域名反写+包的作用,需要全部英文小写,见名知意。

使用规则: 包名.类名     //(全类名/全限定名)

例:

导包:

使用其他类的规则:

①使用同一个包中的类时,不需要导包。

②使用java.lang包中的类时,不需要导包。

③其他情况都需要导包。

④如果同时使用两个包中的同类名,需要用全类名。

例:

package test;

import com.test1.Teacher;

public class Test {
    public static void main(String[] args){
        Animal cat=new Cat();   //Cat类在同一个包 test 中,因此不需要导包和使用全类名,可以直接调用

        Teacher teacher=new Teacher();  //使用test1中的Teacher类,因为不在同一个包中,因此需要使用导包。
                                        //不存在不同包的同名类,不需要使用全类名。

        com.test2.Teacher teacher1=new com.test2.Teacher();  //不同包中有同样的类,因此test2中需要使用全类名而不能导包
    }
}

导包和全类名是两种调用其他包中类的手段。

二十一、修饰符final

规则:

如果用final修饰方法:表明该方法是最终方法,不能被重写。

如果用final修饰类:表示该类是最终类,不能被继承,不能有子类了。

如果用final修饰变量:这个量被称为常量,只能被赋值一次。

例:

Tips:

如果final修饰的变量是基本数据类型,那么变量存储的数据值不能改变。

如果final修饰的变量是引用数据类型,那么变量存储的地址值不能发生改变,对象内部的属性值可以改变。

字符串之所以不可变,就是因为原码中用final修饰。

例:

常量:

实际开发中,常量一般作为系统的配置信息,方便维护,提高可读性。

常量命名规范:

单个单词:全部大写

多个单词:全部大写,单词之间用下划线隔开

二十二、权限修饰符

权限修饰符:用来控制一个成员能够被访问的范围。

可以修饰成员变量、方法、构造方法、内部类。

分类:

四种,范围从小到大: private<空着不写(缺省/默认)<protected<public

private 只能自己用

空着不写   只能本包使用

protected  受保护的     (不同包下的子类:继承可以跨包继承)        

public    公共的

实际开发一般只有 public 和 private:

①成员变量一般是私有

②方法一般是公开

特例:如果方法中代码为抽取别的方法中的共性代码,这个方法一般也私有。

二十三、代码块

分类:

局部代码块、构造代码块、静态代码块

局部代码块:

省内存,括号内的变量在括号执行结束时会从内存中删除。

例:

构造代码块:

定义:写在成员位置的代码块

作用:可以把多个构造方法中重复的代码抽取出来

执行时机:创建本类对象的时候会先执行构造代码块再执行构造方法

构造代码块优先于构造方法执行

例子:

package test;

import com.test1.Teacher;

public class Test {
    public static void main(String[] args){
        final Teacher teacher=new Teacher();
    }
}


package com.test1;

public class Teacher {
    private String name;
    private int age;
    {
        System.out.println("我要开始调用构造方法咯");  //构造代码块
    }

    public Teacher() {
        System.out.println("空参构造");
    }
}

输出结果:

静态代码块:

格式: static{ }

特点:需要通过static关键字修饰,随着类的加载而加载,只触发一次、只执行一次。

使用场景:在类加载的时候,做一些数据初始化的时候使用。

例:

package test;

import com.test1.Teacher;

public class Test {
    public static void main(String[] args){
        final Teacher teacher=new Teacher();
        Teacher teacher1=new Teacher();
    }
}

package com.test1;

public class Teacher {
    private String name;
    private int age;

    static {
        System.out.println("静态代码块执行了");
    }
    {
        System.out.println("我要开始调用构造方法咯");
    }

    public Teacher() {
        System.out.println("空参构造");
    }
}

输出结果:

二十四、抽象类和抽象方法

抽象方法:

将共性的行为(方法)抽取到父类中后,由于每一个子类执行内容不一样,所以父类中的方法不能确定具体的方法体,该方法就可以定义为抽象方法。

tips:子类在继承父类时,若父类中存在一个抽象方法,则会强制子类对这个方法进行重写。

抽象类:

若一个类中存在抽象方法,则该类必须声明为抽象类。

抽象方法和抽象类的定义格式:

抽象方法:

public abstract 返回值类型  方法名(参数列表);

抽象类:

public abstract class 类名{ };

注意事项:

①抽象类不能示例化

②抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类。

③可以有构造方法。

④抽象类的子类:要么重写抽象类中的所有抽象方法,要么是抽象类。

二十五、接口

接口:接口就是一种规则,是对行为的抽象。

定义:   public interface 接口名{ }    //interface关键字

接口不能实例化

接口和类之间是实现关系,通过implements关键字表示:

public class 类名 implements 接口名{ }

接口的子类(实现类):要么重写接口中所有的抽象方法,要么是抽象类。

Tips:

①接口和类的实现关系既可以单实现也可以多实现:

public class 类名 implements 接口名1,接口名2 { }

②实现类还可以在继承一个类的同时实现多个接口:

public class 类名 extends 父类 implement 接口名1,接口名2 { }

示例代码:

//接口1
package test;

public interface MakeBaby {
    public abstract void MakeBaby();
}

//接口2
package test;

public interface Swim {
    public abstract void swim();
}

//父类
package test;

public abstract class Animal {
    private String name;

    public Animal(){

    }

    public Animal(String name){
        this.name=name;
    }

    public String getName() {
        return name;
    }

    public void setAge(String name) {
        this.name = name;
    }
    public abstract void eat();

}

//实现两个接口的子类frog
package test;

public class Frog extends Animal implements Swim,MakeBaby{
    @Override
    public void eat(){
        System.out.println("吃虫子");
    }

    public Frog(){
        super();
    }
    public Frog(String name){
        super(name);
    }

    public void swim(){
        System.out.println("青蛙在游泳");
    }
    public void MakeBaby(){
        System.out.println("造蝌蚪");
    }
}

//测试类
package test;

import com.test1.Teacher;

public class Test {
    public static void main(String[] args){
        Frog frog=new Frog("青蛙王子");
        frog.eat();  //吃虫子
        frog.swim();
        frog.MakeBaby();
    }
}

结果: 吃虫子
            青蛙在游泳
            造蝌蚪

接口中成员的特点:

成员变量:①只能是常量  ②默认修饰符:public static final   

构造方法:没有构造方法

成员方法:①只能是抽象方法 ②默认修饰符:public abstract 

Tips:

JDK7以前接口中只能定义抽象方法。

JDK8新特性:接口中可以定义有方法体的方法。

JDK9新特性:接口中可以定义私有方法。

接口和类之间的关系:

类和类的关系:

继承关系,只能单继承,不能多继承,但是可以多层继承。

类和接口的关系:

实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口。

tips:

如果两个接口中存在同名方法,在这个类实现这两个接口时,只要对重名的方法重写一次。

接口和接口的关系:

继承关系,可以单继承,也可以多继承。

例:

//接口1
package test;

public interface Inter {
    void method();
}

//继承接口1的接口2
package test;

public interface Inter2 extends Inter {
    void method2();
}

//继承接口2的接口3
package test;

public interface Inter3 extends Inter2{
    void method3();
}

//实现接口3的类
package test;

public class InterImp1 implements Inter3{
    @Override
    public void method() {
        System.out.println("方法");
    }

    @Override
    public void method2() {

    }

    @Override
    public void method3() {

    }
}


//需要同时重写接口1、接口2和接口3中三个方法

JDK8中接口新增的功能(允许存在有方法体的方法):

(一)默认方法

允许在接口中定义默认方法,需要用关键字default修饰:解决接口升级问题。

接口中默认方法定义格式:

格式: public default 返回值类型 方法名(参数列表){    }

范例: public default void  show(){    }

Tips:

①默认方法不是抽象方法,所以不强制被重写。但是如果被重写,重写时去掉default关键字

②public可以省略,default不能省略。

③如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写。

例(不重写):

package test;

public interface Inter {
    public default void show(){
        System.out.println("接口默认方法");
    }
    void method();
}

package test;

public class InterImp2 implements Inter{
    @Override
    public void method() {

    }

}


package test;

import com.test1.Teacher;

import java.sql.SQLOutput;

public class Test{
    public static void main(String[] args){
        InterImp2 inter=new InterImp2();
        inter.show();   //默认方法
    }
}


(重写):

package test;

public interface Inter {
    public default void show(){
        System.out.println("接口默认方法");
    }
    void method();
}

package test;

public class  InterImp2 implements Inter{
    @Override
    public void method() {

    }

    @Override
    public void show() {
        System.out.println("重写方法");
    }
}

package test;

import com.test1.Teacher;

import java.sql.SQLOutput;

public class Test{
    public static void main(String[] args){
        InterImp2 inter=new InterImp2();
        inter.show();   //重写方法
    }
}



(二)静态方法

允许在接口中定义静态方法,需要用static修饰

定义格式:

格式:public static 返回值类型 方法名(参数列表){   }

范例:public static void show(){  }

Tips:

①静态方法只能通过接口名调用,不能通过实现类名或者对象名调用。

②public可以省略,static不能省略。

例:

package test;

public interface Inter {
    public default void show(){
        System.out.println("接口默认方法");
    }
    void method();

    public static void look(){   //接口中定义的静态方法
        System.out.println("静态方法看一看咯");   
    }
}

package test;

public class  InterImp2 implements Inter{
    @Override
    public void method() {

    }

  //实现类中不需要对静态方法进行重写

    @Override
    public void show() {
        System.out.println("重写方法");
    }
}

package test;

import com.test1.Teacher;

import java.sql.SQLOutput;

public class Test{
    public static void main(String[] args){
        Inter.look();  //直接用接口名调用
    }
}



JDK9以后接口中新增的功能(允许定义私有方法):

定义格式:

格式1:private 返回值类型 方法名(参数列表) {   }

范例1:private void show() {  }

格式2: private static 返回值类型 方法名(参数列表) {  }

范例2:private static void method() {  }

package test;

public interface InterA {
    public default void show1(){
        System.out.println("SHOW1方法开始执行");
        System.out.println("记录程序细节:(省略100行代码)");
    }

    public default void show2(){
        System.out.println("SHOW2方法执行");
        System.out.println("记录程序细节:(省略100行代码)");
    }

}

可以看到接口中        System.out.println("记录程序细节:(省略100行代码)"); 这部分代码重复

JDK9以前采用将该部分额外设立成一个默认方法来避免重复:

package test;

public interface InterA {
    public default void show1(){
        System.out.println("SHOW1方法开始执行");
        show();
    }

    public default void show2(){
        System.out.println("SHOW2方法执行");
        show();
    }

    public default void show(){
        System.out.println("记录程序细节:(省略100行代码)");
    }
}

这就导致了show()方法可以被外界调用,为了避免调用,JDK9允许将其设置为私有方法:

package test;

public interface InterA {
    public default void show1(){
        System.out.println("SHOW1方法开始执行");
        show();
    }

    public default void show2(){
        System.out.println("SHOW2方法执行");
        show();
    }
    
    public static void show3(){
        System.out.println("SHOW3方法执行");
        show5();
    }

    public static void show4(){
        System.out.println("SHOW4方法执行");
        show5();
    }

    private  void show(){  //为默认方法服务
        System.out.println("记录程序细节:(省略100行代码)");
    }
    private static void show5(){  //为静态方法服务
        System.out.println("记录程序细节:(省略100行代码)");
    }
}

普通的私有方法是为默认方法服务的,静态的私有方法是为静态方法服务的。

总结:

①接口代表规则,是行为的抽象。想让哪一个类拥有一个行为,就让这个类实现对应的接口就可以了。

②当一个方法的参数是接口时,可以传递接口所有实现的对象,这种方式称为接口的多态。

图中 有两个类 一个是车类 一个是搬家公司类  两个类都实现了运输这一个接口,因此在调用搬家这个方法时,假设方法的参数类型设定为接口,那么使用方法时,参数既可以设定为车的对象,也可以设定为搬家公司的对象。

适配器模式

当一个接口中抽象方法过多,但是用户只需要使用其中一部分的时候,就可以适配器设计模式。

书写步骤:

编写中间类  XXXXAdapter,实现对应接口。对接口中的抽线方法进行空实现。

再让真正的实现类继承这个中间类,重写自己需要的方法。

为了避免其他类创建适配器类的对象,中间的适配器类用abstract修饰。

二十六、内部类

类的五大成员:

属性、方法、构造方法、代码块、内部类

内部类:在一个类的里面,再定义的一个类。

例:

内部类的种类:

成员内部类、静态内部类、局部内部类、匿名内部类

(一)成员内部类

写在成员位置的,属于外部类的成员。

可以被一些修饰符所修饰,如:private、默认、protected、public、static等

在成员内部类里,JDK16之前不能定义静态变量,JDK16开始可以定义静态变量。

获取成员内部类对象:

方式一: 在外部类创建方法,对外提供内部类对象

方法二:直接创建格式: 外部类名.内部类名  对象名=外部类对象.内部类对象;

例(Engine类不是被private修饰情况下):

package test;

public class Car {
    String carName;
    int carAge;
    String carColor;

    class Engine{
        String engineName;
        int engineAge;
    }
}

package test;

import com.test1.Teacher;

import java.sql.SQLOutput;

public class Test{
    public static void main(String[] args){
        Car car=new Car();
        Car.Engine engine=new Car().new Engine();
    }
}

另一种情况:

package test;

public class Car {
    String carName;
    int carAge;
    String carColor;

    private class Engine{
        String engineName;
        int engineAge;
    }

    public Engine getEngineName(){
        return new Engine();
    }
}


package test;

import com.test1.Teacher;

import java.sql.SQLOutput;

public class Test{
    public static void main(String[] args){
        Car car=new Car();
        System.out.println(new Car().getEngineName());
    }
}


成员内部类获取外部类的变量:
package test;

public class Car {
    String carName;
    int carAge;
    String carColor;

    int a=10;

    class Engine{
        String engineName;
        int engineAge;
        int a=20;
        public void show(){
            int a=30;
            System.out.println(a);           //30
            System.out.println(this.a);      //20
            System.out.println(Car.this.a);   //10     //Car.this代表着Car类的地址
        }
    }

    public Engine getEngineName(){
        return new Engine();
    }
}

package test;

import com.test1.Teacher;

import java.sql.SQLOutput;

public class Test{
    public static void main(String[] args){
        Car car=new Car();
        System.out.println(new Car().getEngineName());

        Car.Engine engine=new Car().new Engine();
        engine.show();
    }
}


(二)静态内部类

静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象。

创建格式:

外部类名.内部类名 对象名=new 外部类名.内部类名();

例:(engine类是Train类的静态内部类)

Train.engine test=new Train.engine();  //创建静态内部对象

调用非静态方法的格式:先创建对象,用对象名调用。

例:(test是创建的静态内部类的对象,show1方法是静态内部类中的非静态方法)

package test;

public class Train {
    static class engine{


        public void show1(){
            System.out.println("非静态方法show1");
        }

        static void show2(){
            System.out.println("静态方法show2");
        }
    }
}
package test;

import com.test1.Teacher;

import java.sql.SQLOutput;

public class Test{
    public static void main(String[] args){
        Train.engine test=new Train.engine();  //创建静态内部对象
        test.show1();//调用静态内部类中的非静态方法
    }

}

调用静态方法的格式:外部类名.内部类名.方法名();

package test;

import com.test1.Teacher;

import java.sql.SQLOutput;

public class Test{
    public static void main(String[] args){
        Train.engine test=new Train.engine();  //创建静态内部对象
        Train.engine.show2();  //调用静态内部类中的静态方法
    }
}

(三)局部内部类

①将内部类定义在方法里面就叫做局部内部类,类似于方法里的局部变量。

②外界是无法直接使用,需要在方法内部创建对象并使用。

③该类可以直接访问外部类的成员,也可以访问方法内的局部变量。

①例:下图中的局部内部类Inner和局部变量 a 类似

②例:

package test;

public class Train {

    public void show(){
        int a=10;

        class Inner{
            String name;
            int age;
            public void method1(){
                System.out.println("局部内部类的非静态方法");
            }

            public static void method2(){
                System.out.println("局部内部类的静态方法");
            }
        }

        Inner i=new Inner();
        System.out.println(i.name);
        System.out.println(i.age);
        i.method1();
        Inner.method2();     //静态方法调用时使用类名调用
                             //或者使用对象名调用: i.method2();

    }
}

(四)匿名内部类

匿名内部类本质上就是隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置。

格式:  

new 类名或者接口名() {   重写方法;};   

例: new Inter(){ public void show(){   }   }


package test;

public interface Swim { //接口
    public abstract void swim();
}


package test;

public abstract class Dog { //抽象类
    public abstract void eat();
}


package test;

import com.test1.Teacher;

import java.sql.SQLOutput;

public class Test{  ///测试类
    public static void main(String[] args){
        new Swim(){  //匿名内部类 (接口)一个实现了Swim接口的没有名字的类
            @Override
            public void swim() {
                System.out.println("重写了游泳的方法");
            }
        };

        new Dog(){  //匿名内部类(类)  一个继承了狗类的没有名字的类
            @Override
            public void eat() {
                System.out.println("狗吃骨头");
            }
        };

        //一个作为狗类的子类的匿名内部类实现的多态     
        method(
             new Dog() {      //一个继承狗类的子类
                         @Override
                         public void eat() {
                          }
                        });
    }
    public static void method(Dog dog){
        dog.eat();
    }
}

使用场景:当方法的参数是接口或者类时,以接口为例,可以传递这个接口的实现类对象,如果实现类只使用一次,就可以使用匿名内部类简化代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值