3.4—4 Java final关键字、接口、数组

一、final 关键字

final修饰属性、方法、类

  • 修饰属性:修饰的属性是常量,必须直接赋值、或在构造方法中赋值

    • 定义时直接赋值

      static final int num =10; //常量不可变 ,所以直接写在模板上,故而 static final 推荐一起使用

    • 定义时,没有赋值,在构造方法中赋值,在每个对象中都可以拥有一个常量

      final int count ; //在构造方法中赋初值

      public FinalDemo ( int count ){ // 每新建一个对象,就为属性赋值,赋值后,值就不能改变

      ​ this.count = count;

      }

  • 修饰方法:子类中不可以重写

  • 修饰类 :不可以被继承, 不能修饰为抽象类或接口

package com.feifan.javaoop.day5;
/*
    final 修饰  类、属性、方法
        修饰类:  不能修饰抽象类、接口,修饰的类不能被继承
        修饰方法: 不能修饰抽象方法,修饰的方法不能被子类重写
        修饰属性: 修饰后的属性是 常量,值不可以改变,必须初始化赋值  或 初试化构造方法赋值
                 1)直接初始化赋值    值就在方法区里的模板上,值是确定的,大家共享, 推荐使用static final
                 2)初始化构造方法赋值     每新建一个对象,就为属性赋值,赋值后值就不能改变了

 */
public class  FinalDemo{

    // final修饰类   public final class String{}

    // final修饰属性
    // ctrl + 鼠标左键 进入底层查看String代码      private final char value[];
    String s = "abc"; //字符串在底层是以数组形式存储 char [a,b,c]  字符串的值不能改变

    //属性在定义时直接赋值
    final int num = 10; //值不可以改变,推荐static final组合使用,整个内存中存一份

    //属性在定义时没有为常量赋值,使用构造方法赋值,在每个对象中都可以拥有一个常量使用
    final int count;//每创建一个对象时,为常量count赋值


    public FinalDemo(int count) {
        this.count = count;
    }


    public  void test(){

        //测试final修饰的num值能否改变
        //num =100; 报错


        new String("a");
        new FinalDemo(10); //测试在定义时没有为属性赋值,通过构造方法赋值
        new FinalDemo(20); //每新建一个对象时,给属性赋值,赋值后就不能改变
    }


/*    //final修饰方法 不能被子类重写  final不能修饰构造方法
    public final void test(){
        //测试final修饰的方法能否被子类重写
    }*/
}

二、接口 (interface、 implement)

1、什么是接口?

  • 顶层的功能定义 ,专注于功能设计,而不是实现,让其他类具体实现
  • 与抽象类相似,但有区别,接口实现多继承的逻辑
  • 用多态方法使用

1)生活中的接口----USB接口

  • USB接口本身没有实现任何功能

    USB接口规定了数据传输的要求

    USB接口可以被多种USB设备实现

只要有USB接口,就可以通过USB风扇,USB鼠标,U盘 具体实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dabXpqsb-1642950372831)(C:\Users\16431\AppData\Roaming\Typora\typora-user-images\image-20220123162439599.png)]

那怎么实现? 可以使用java接口来实现

  • 编写USB接口---->通过需求设计方法 顶层 抽象的

  • 实现USB接口---->实现所有方法

  • 使用USB接口---->用多态方式使用 具体怎么用多态方式实现?

    • 复习下多态:
      • 多态使用场景: 喂不同动物吃,动物吃东西
      • 多态三个条件: 继承、重写、父类引用指向子类对象
      • 向上转型: 子类调用父类方法
      • 向下转型:父类调用子类自身特有的方法

2)面向接口编程

程序设计时:

  1. 关心实现类有何能力,而不关心实现细节
  2. 面向接口的约定而不考虑接口的具体实现

3)接口存在意义?

java中一个类只能有一个父类,所以接口可以实现多继承的逻辑

2、接口怎么用?

简单总结:

1)接口定义 ( interface )

[访问权限修饰符 ] interface 接口名称 [extends 其他接口名1,…其他接口名n]{

​ //1、静态属性 public static final

​ //2、抽象方法 public abstract

​ 子类不能进行选择性地对所有抽象方法进行重写,要重写就得对所有抽象方法全部重写

​ //3、静态方法 public static void

​ //4、默认方法 public default void

​ 子类可以选择是否对定义的默认方法重写

}

2)接口实现 ( implements )
  • [访问权限修饰符] class 类名 implements 接口1 ,接口2 …{ }

  • 结合继承:

    ​ [访问权限修饰符] class 类名 extends 父类名 implements 接口1 ,接口2 …{ }

3)接口使用实例—Animal CanCry() CanFly()
  • ​ **接口是功能上的定义,**比如CanCry () CanFly()
  • 抽象类除了功能定义还有类的成员变量,比如Animal 类中除了抽象方法还有成员变量

1)接口定义格式

  • 接口——interface声明

    1. 接口中静态属性——默认public static final ,就是静态常量

      接口中定义的属性用大写字母定义,比如:public static final PI =3.14;

    2. 接口中抽象方法——默认pubic abstract

    3. 接口中静态方法——接口可直接调用 public static

    4. 接口中默认方法——通过子类调用 public default

    public interface MyInterface{ //interface 关键字定义类

    ​ int num; //所有属性默认为 public static final 静态常量

    ​ public void foo(); // 抽象方法是:public abstract

    ​ public static void test() {

    ​ //jdk8之后添加静态方法,接口可直接调用

    ​ }

    ​ public default void test1(){

    ​ //jdk8之后添加默认方法,通过子类调用

    ​ }

    }

package com.feifan.javaoop.day5;

public interface MyInterface{
    /*
        1、接口中定义属性:
            就是常量  用大写字母命名
            默认public static final
     */
//    public static final int NUM = 10; //必须赋值
    int NUM = 10; //接口中定义的属性默认是静态常量

    /*
        2、接口中定义的方法:
            默认public abstract
            子类对抽象方法重写时,会对所有抽象方法重写
     */
//    public abstract void eat();
    void eat();
    void sleep();

    /*
        //java8 之后, 新增了两种方法
        3、静态方法
            public static
        4、默认方法
            public default
     */
    //静态方法   接口自己调用
    public static void test1(){
        System.out.println("test1是接口中的静态方法,"+"接口中的属性NUM="+NUM);
    }

    //默认方法  是让子类重写,或让子类调用, 子类可以有选择地对默认方法重写
    public default void test2(){
        System.out.println("test2是接口中的默认方法,");
    }

}
//----------------------------------------------------------------------
package com.feifan.javaoop.day5;

public class TestMyInterface {

    public static void main(String[] args) {

        System.out.println(MyInterface.NUM);//测试接口中的属性

        MyInterface.test1();//测试接口中的静态方法,通过接口名调用
    }
}

2)接口实现格式

  • 类使用 implements关键字来实现接口

    • implements:实现
    • [访问权限修饰符] class 类名 implements 接口1 ,接口2 …{ }
    • 结合继承: [访问权限修饰符] class 类名 extends 父类名 implements 接口1 ,接口2 …{ }
  • 实现接口的 类命名 ,公认的写法后加 Impl

    • MyInterfaceImpl 前面:接口名,后面:Impl 表示接口类的实现

3、接口特性?

  1. 接口是隐式抽象的 ,声明接口时不需要abstract
  2. 接口中的方法可以是抽象的、静态的、默认的
  3. 接口中属性默认 public static final
  4. 接口不是被类继承,而是被类实现
  5. 接口不能实例化对象,无构造方法
  6. 一个类可以实现多个接口
  7. 与继承关系相似,接口与实现类之间存在多态
  8. 一个接口能继承其他多个接口
  9. 当类实现接口时,类要实现接口中的抽象方法,否则,类必须声明为抽象类

4、接口实例----Animal CanCry() CanFly()

**接口是功能上的定义,**比如CanCry () CanFly()

**抽象类除了功能定义还有类的成员变量,**比如Animal 类中除了抽象方法还有成员变量

package com.feifan.javaoop.day5.InterfaceDemo;

public abstract class Animal{

    private String name;

    public Animal() {

    }

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


    //动物的共性  抽象类
    public abstract  void eat();
    public abstract  void sleep();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.feifan.javaoop.day5.InterfaceDemo;

public interface CanCry {  // 动物功能  接口
    void cry();
}
package com.feifan.javaoop.day5.InterfaceDemo;

public interface CanFly {  // 动物功能  接口
    void fly();
}
package com.feifan.javaoop.day5.InterfaceDemo;

public class Bird extends  Animal implements CanFly, CanCry {

	

    @Override
    public void eat() {  // 继承和接口实现 都需要重写方法

    }

    @Override
    public void sleep() {

    }

    @Override
    public void fly() {

    }

    @Override
    public void cry() {

    }
}
package com.feifan.javaoop.day5.InterfaceDemo;

public class Dog extends Animal  {
    @Override
    public void eat() {   // Dog没有implements CanCry,所以不能使用多态

    }

    @Override
    public void sleep() {

    }
}
package com.feifan.javaoop.day5.InterfaceDemo;

public class Test {
    public static void main(String[] args) {
        Animal bird = new Bird(); //多态
        CanFly b = new Bird();//接口也可以实现多态方法
        CanCry c = new Bird();
        
//        CanCry d = new Dog();//错误 Dog类没有implements CanCry,所以不能通过CanCry声明
    }
}

3、抽象类和接口区别

  • 想实例 ,抽象类Animal 中有抽象方法eat() , sleep() ,这些是动物共性 。

    然后设计接口CanCry CanFly 是一些动物实例对象的功能 。

    比如鸟能叫,鸟能飞,而狗能叫,但狗不能飞, Bird 类 implements CanCry CanFly , 那么新建一个Brid对象时,就可以使用多态,接口引用 指向 Brid对象,类似于继承中的多态,通过子类调用父类中的方法(向上转型、向下转型),就可以通过新建的 Brid对象 实现接口 。

  • **接口是功能上的定义,**比如CanCry () CanFly()

  • 抽象类除了功能定义还有类的成员变量,比如Animal 类中除了抽象方法还有成员变量

1)相同点:

  1. 都不能创建对象
  2. 都可以表示多态性 (座位父类)

2)不同点:

  • 接口:
    1. 接口不能有构造方法
    2. 不能有成员变量,只能有静态属性
    3. 不能有成员方法,只能有静态方法,默认方法
  • 抽象类
    1. 抽象类能有构造方法
    2. 能有成员变量

4、抽象类和接口的关系?

  1. 一个类只能继承一个父类 ---- 类和类

  2. 一个类可以实现多个接口 ---- 类和接口

  3. 一个接口可以继承多个接口 ----- 接口和接口

package com.feifan.javaoop.day5;

public class InterfaceA {
}
package com.feifan.javaoop.day5;

public class InterfaceB {
}
package com.feifan.javaoop.day5;

public class InterfaceC {
}
package com.feifan.javaoop.day5;

public interface MyInterface extends InterfaceB, InterfaceC{
    
}
package com.feifan.javaoop.day5;

/*
    一个类只能继承一个父类
    一个类可以实现多个接口
    一个接口可以继承多个接口
 */
public class MyInterfaceImpl extends  Object implements  MyInterface, InterfaceA{

    /*
        一个类实现接口,要么将此类声明为抽象类
                    要么重写接口中的所有抽象方法
     */

    /*
           MyInterfaceImpl 类 实现 InterfaceA 和 MyInterface 两个接口,
           而 MyInterface接口又继承 InterfaceB,InterfaceC 两个接口,
           所以 MyInterfaceImpl 相当于实现 InterfaceA、 MyInterface、 InterfaceB、和 InterfaceC 四个接口
           所以 MyInterfaceImpl 要对 四个接口中的方法都进行重写
           从而实现一个类 多继承 的逻辑
     */
    @Override
    public void eat() {

    }

    @Override
    public void sleep() {

    }



    /*
        默认方法可以重写,也可以不重写
     */
    @Override
    public void test2() {

    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nELZC0Gj-1642950372834)(C:\Users\16431\AppData\Roaming\Typora\typora-user-images\image-20220123184643345.png)]

三、数组

1、什么是数组?

  • 数组是一组数据类型相同的数据集合
  • 数组是引用数据类型,即 数组是对象
  • 数组创建时必须有指定长度,创建后长度不可变,空间中内存是连续的
  • 数组可以存储基本数据类型,也可以存储引用数据类型

面试题:现有5MB大小内存空间,能否创建3MB大小的内存空间?

答案:不一定 , 5M空间中可能没有连续的3M, 数组必须是连续的内存空间

2、 数组的声明和创建

1)数组声明

  • int [] m; //建议使用这种方式
  • int n [];

2)数组创建

  • int [] a = new int[5];
  • int [] a1 = new int[]{1,2,3,4,5};
  • int [] a3 = {1,2,3,4,5};
package com.ffyc.javaarray;

import java.util.Arrays;

public class Demo {
    /*
        数组:一组数据   一组数据类型相同的数据
            数组是对象,里面可以有指定长度的连续空间
            数组内存空间必须是连续的
            创建时指定长度

        面试题:现有5MB大小内存空间,能否创建3MB大小的内存空间?
            答案:不一定 , 5M空间中可能没有连续的3M
     */
    public static void main(String[] args) {
        
        /* 声明数组:2种方式
            int 表示数组对象中可以存储的数据类型是int
            []  表示是数组
            a 就是数组对象的引用
        */
        int [] m; //建议使用这种方式
        int n [];

        /* 创建数组:3种方法
           动态创建数组(没有为数组赋值,可以结合for循环赋值)1、 静态创建数组(创建时就赋初值)2、3
             数组是对象
             创建数组必须指定长度,数组长度一旦定义,就不能改变,因为数组空间必须是连续的
             数组可以是数据类型,也可以是引用类型
        */

        //1、创建了数组对象,分配了空间,为空间分配了默认值,后期再对数组赋值操作
        int [] a = new int[5];
        long [] b = new long[5];
        char [] c = new char[5];
        boolean [] d = new boolean[5];
        String [] s = new String[5];
        System.out.println(a.length);   //10
        System.out.println(a);  //[I@1b6d3586 输出的是地址,默认调用Objec类中的toString(),将对象以字符串形式展示
        System.out.println(Arrays.toString(a)); //[0, 0, 0, 0, 0] toString 将数组内容以字符串形式输出
        System.out.println(Arrays.toString(b)); //[0, 0, 0, 0, 0]
        System.out.println(Arrays.toString(c)); //[ ,  ,  ,  ,  ]
        System.out.println(Arrays.toString(d)); //[false, false, false, false, false]
        System.out.println(Arrays.toString(s)); //[null, null, null, null, null]

        //2、创建数组对象时,直接对数组内容进行填充
        int [] a1 = new int[]{1,2,3,4,5};
        System.out.println(a1);//[I@4554617c
        System.out.println(Arrays.toString(a1));//[1, 2, 3, 4, 5]  将数组内容以字符串形式输出

        //3、数组内容已知,就可以简化
        int [] a3 = {1,2,3,4,5};
        System.out.println(a3);//[I@74a14482
        System.out.println(Arrays.toString(a3));//[1, 2, 3, 4, 5]
    }
}

3、 数组的访问和迭代

1)数组元素的访问

  • 数组名 [ index ] index 索引、下标
  • 索引从0开始
  • 索引最大值和数组长度差1

2)数组迭代

重复执行程序中的循环,直到满足某条件为止,亦称为迭代。

  • 数组迭代 两种方式: for循环 、 增强for循环
for循环 和 增强for循环区别
  • for 循环有下标 ,可以对数组内按数组下标访问
  • 增强for循环 , 只能遍历出数组中的元素
package com.ffyc.javaarray;

import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
import org.w3c.dom.ls.LSOutput;

public class Demo3 {
    public static void main(String[] args) {
        /*
            对数组的遍历 --> 通过循环实现
            数组索引 index
        */
        int [] c = {1,2,4,3,5};
        System.out.println(c.length);//通过length属性获取数组长度
        for (int i = 0; i < c.length; i++) {
            System.out.println(c[i]);
        }

        //jdk5 之后 推出了增强for循环,如果只需要遍历,可以使用增强for
        /*
            c 需要遍历的数组
            int t 声明了一个变量
            每次从数组c中,取出一个元素,赋给零时变量t
         */
        for(int t : c){
            System.out.println(t);
        }
    }
}

4、数组排序

1)冒泡排序

比较两个相邻的元素,将值 大/小 的元素交换到右边

package com.ffyc.javaarray;

public class BubbleSortDemo {
    // 冒泡排序
    //比较两个相邻的元素,将值大/小的元素交换到右边
    public static void main(String[] args) {

        int [] a = new int[]{1,4,3,5,6};
        System.out.println("数组长度为:"+a.length);

        System.out.println("排序前:");
        for( int t : a ){ //增强for循环
            System.out.print(t+"\t");
        }

        System.out.println("\n"+"排序后:");
        BubbleSortDemo bubbleSortDemo = new BubbleSortDemo();
        bubbleSortDemo.BubbleSort1(a, a.length);
        System.out.println("从小到大排序:");
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i]+"\t");
        }
        System.out.println("\n"+"从大到小排序:");
        bubbleSortDemo.BubbleSort2(a, a.length);
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i]+"\t");
        }
    }


    //冒泡排序 从小到大
    public void BubbleSort1(int a[],int lenght){
        for (int j = 0; j < lenght -1; j++) {
            for (int i = 0; i < lenght -1; i++) {
                if (a[i] > a[i+1]){
                    int temp = a[i+1];
                    a[i+1] = a[i];
                    a[i] = temp;
                }
            }

        }

    }
    //冒泡排序 从大到小
    public void BubbleSort2(int a[],int lenght){
        for (int j = 0; j < lenght -1; j++) {
            for (int i = 0; i < lenght -1; i++) {
                if (a[i] < a[i+1]){
                    int temp = a[i];
                    a[i] = a[i+1];
                    a[i+1] = temp;
                }
            }

        }
    }
}

数组长度为:5
排序前:
1 4 3 5 6
排序后:
从小到大排序:
1 3 4 5 6
从大到小排序:
6 5 4 3 1

2)选择排序

思想是: 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

package com.ffyc.javaarray;

public class SelectionSortDemo {
    public static void main(String[] args) {
        int [] a = {1,5,4,7,0,2,5};
        System.out.println("数组长度为:"+a.length);
        //排序前
        System.out.println("排序前:");
        for(int temp : a){
            System.out.print(temp+"\t");
        }
        //排序后
        System.out.println("\n从小到大排序:");
        SelectionSortDemo selectionSortDemo = new SelectionSortDemo();
        selectionSortDemo.SelectionSort1(a, a.length);
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i]+"\t");
        }

        System.out.println("\n从大到小排序:");
        selectionSortDemo.SelectionSort2(a, a.length);
        for(int temp : a){
            System.out.print(temp+"\t");
        }
    }
    //从小到大
    public  void SelectionSort1(int [] a, int length) {
        for (int i = 0; i < a.length - 1; i++) {
            int minIndex = i;
            // 每一个元素都和剩下的未排序的元素比较
            for (int j = i + 1; j < a.length; j++) {
                if (a[j] < a[minIndex]) {
                    minIndex = j;//将最小数的索引保存
                }
            }
            //经过一轮循环,就可以找出第一个最小值的索引,然后把最小值放到i的位置
            swap(a, i, minIndex);
        }
    }
    // 从大到小
    public  void SelectionSort2(int [] a, int length){
        for (int i = 0; i < a.length - 1; i++) {
            int maxIndex = i;
            // 每一个元素都和剩下的未排序的元素比较
            for (int j = i + 1; j < a.length; j++) {
                if (a[j] > a[maxIndex]) {
                    maxIndex = j;//将最大数的索引保存
                }
            }
            //经过一轮循环,就可以找出第一个最大值的索引,然后把最大值放到i的位置
            swap(a, i, maxIndex);
        }
    }
    public void swap(int [] a, int i, int j){
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}

数组长度为:7
排序前:
1 5 4 7 0 2 5
从小到大排序:
0 1 2 4 5 5 7
从大到小排序:
7 5 5 4 2 1 0

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码元宋大米

感谢小主大赏,留言可进互助群~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值