Java学习_从构造方法到Lambda表达式

一、构造方法

  1. 方法名和类名一致,没有void,没有具体的返回值类型。

  2. 构造方法支持重载

  3. 注意事项

    1. 系统默认提供无参构造方法。
    2. 如果写了有参构造方法,系统就不会自动生成无参构造方法。
    
  4. 成员变量的赋值方法

    1. setXXX(参数)赋值
    2. 有参构造器赋值
  5. 构造方法私有化后,使成员方法静态化(加入static),直接用 类名.方法名 调用。方便使用。(如工具类就是如此)

    工具类

    import java.util.Arrays;
    
    public class Tools {
        //私有化构造方法,使外部方法无法new对象,只能使用类名.方法名调用
        private Tools() {
        }
        
        //构造方法私有化后,要想使用成员方法,必须将成员方法静态化,使其在类加载时加载
        //加法
        public static int sum(int... nums) {
            int temp = 0;
            for (int i = 0; i < nums.length; i++) {
                temp += nums[i];
            }
            return temp;
        }
    
        //减法
        public static int sub(int... nums) {
            int temp = 0;
            for (int i = 0; i < nums.length; i++) {
                temp = nums[0];
                temp -= nums[i];
            }
            return temp;
        }
    
        //乘法
        public static int mult(int... nums) {
            int temp = 1;
            for (int i = 0; i < nums.length; i++) {
                temp = nums[i] * temp;
            }
            return temp;
        }
    
        //除法
        public static double divsion(int... nums) {
            double temp = -1;
            boolean flag = true;
            for (int j = 0; j < nums.length; j++) {
                if (nums[j] == 0){
                    flag = false;
                    break;
                }
            }
            for (int i = 0; i < nums.length; i++) {
                if (flag){
                    temp = nums[0];
                    temp /= (double)nums[i] ;
                }
            }
            return temp;
        }
    
        //冒泡排序
        public static void bubble(int[] arr) {
            for (int i = 0; i < arr.length - 1; i++) {
                for (int j = 0; j < arr.length - 1 - i; j++) {
                    if (arr[i] < arr[i + 1]) {
                        int temp = arr[i];
                        arr[i] = arr[i + 1];
                        arr[i + 1] = arr[i];
                    }
                }
            }
            System.out.println(Arrays.toString(arr));
        }
    }
    

    测试类

    public class ToolsTest {
        public static void main(String[] args) {
            //加法
            System.out.println("加出的结果是:"+Tools.sum(1,2,3));
            //减法
            System.out.println("减出的结果是:"+Tools.sub(12,2,2));
            //乘法
            System.out.println("乘出的结果是:"+Tools.mult(3,4,5));
            //除法
            System.out.println("除法出的结果是:"+Tools.divsion(3,0));
    
            //冒泡排序
            int[] arr = {12,34,45,65,6,66,76,77,8,785};
            Tools.bubble(arr);
        }
    }
    

二、类中的成员

  1. 标准类

    成员变量
    成员方法
    构造方法
        无参构造方法(都给)
        有参构造方法(视情况给出)
    
  2. 成员变量

    类中的变量
    

三、static

  1. 被static修饰符的变量及方法 被称为类成员,随着类的加载而加载。

  2. 优先于对象存在。也就不能与this共存(this依赖于对象存在)。

  3. static能体现共享、共用的含义,如果需求中有’共用’的含义,这个变量直接使用static修饰。

  4. 被static修饰的成员(变量/方法)访问方式:

    1. 类名.变量名 类名.方法名 推荐使用
    2. 对象名.变量名 对象名.方法名 不推荐使用
  5. 非静态的方法既可以访问静态的,也可以访问非静态的方法。

    静态的方法只能访问静态的方法。

四、代码块

  1. 静态代码块

    类一加载,静态代码块先执行,类只加载一次,静态代码块也只加载一次。

    静态代码块>局部代码块>构造方法

    static {
        
    }
    1. 位置:类的成员位置
    2. 作用:
    3. 应用:读取配置文件、完成核心文件的加载
    
    

    因为类只加载一次,所以static代码块也只加载一次。

  2. 构造代码块

    优先级:构造代码块>构造方法

    每创建一个对象,就执行一次构造代码块。

    1. 在类成员的位置
        如果类中有,先执行构造代码块,再执行构造方法。
    
    2. 可以将构造方法中共性的内容,提取到代码块中。 
    
  3. 局部代码块

    作用:限定某个变量的生命周期
    
  4. 加载顺序:

    静态代码块>构造代码块>构造方法

五、继承

写父类时,所有都显式给出无参构造方法

子类所有构造方法,都默认访问父类的无参构造方法

  1. 概念

    将多个子类的共性内容,抽取到一个独立的类中,多个类和独立类产生的一种关系称为继承

  2. 继承的三种类型

    在这里插入图片描述

  3. 特点(好处):

    1. 提高了代码的复用性
    2. 提高了代码的可维护性
    3. 是多态的前提条件
  4. 弊端

    继承关系存在局限性,继承的父类方法可能不完全用到。造成耦合度变高

  5. 注意事项

    • 子类只能继承父类非 私有成员,私有成员,可间接访问。
    • 构造方法不能继承,只能间接访问
  6. 继承的成员变量的访问:

    • 子类继承父类,成员变量名不一致,分别访问即可
    • 子类继承父类,成员变量名一致,访问采用就近原则
      • 首先在子类的局部位置找
      • 在子类的成员位置找
      • 在父类的成员位置找
      • 父类没有,继续往上找,如果没有,则报错。
  7. 继承的构造方法访问:

    • 子类所有构造方法默认访问,父类的无参构造方法。
    • 子类的所有构造方法的第一句默认都是super(),可以不写。
  8. 继承的成员方法的访问:

    • 成员方法名不一致,分别调用即可
    • 成员方法名一致,而且一模一样,则方法重写。重写的时候必须要保证它的访问权限足够大。

六、Student s = new Student() 完成的事情

  1. 加载类
  2. 开辟栈内存空间Student s
  3. 申请堆内存空间,进行系统默认初始化(通过无参构造方法)
  4. 初始化完毕,产生堆内存空间地址
  5. 将堆内存空间地址赋值给栈内存变量s
  6. 栈内存变量s指向堆内存地址。

七、成员变量和静态变量的区别

存储位置不同:
    成员变量:堆内存中
    静态变量:static静态区中
生命周期不同:
    成员变量:随着对象的创建而存在,随着对象的创建完毕等待垃圾回收而消失(不会立即回收)
    静态变量:随着类的加载而存在,随着类的加载完毕而消失(非自定义常量)
初始化不同:
    成员变量:可以不初始化,存在默认初始化,通过setXXX(xx)或者有参构造方法显示初始化
    静态变量:可以不初始化,或者直接初始化,可可以通过类名.变量名=赋值。
访问方式不同:
	成员变量:创建对象访问
	静态变量:使用类名.变量名访问

八、super

  1. 表示父类的空间标识

    //访问父类属性
    super.父类变量名
        
    //访问父类方法
    super.方法名()
        
    //访问父类构造方法
    super()
    

九、override 重写

  1. 概念

    子类中出现了和父类中一模一样的方法声明,子类将父类方法覆盖,实现自己的方法,也被称为方法覆盖,方法复写。

  2. 注意事项

    • 父类中私有方法不能被重写
    • 子类重写父类方法时,访问权限不能更低
    • 父类静态方法,子类也必须通过静态方法进行重写。(算不上方法重写)
  3. 不想让子类重写方法可以在方法中加入final关键字。

十、final

  1. 表示最终的,不能被重写

  2. final常和static一起使用。

    如:public static final int x = 100;

    表示常量,无法修改(重新赋值)

  3. 编译时期常量:jvm不需要加载

  4. 运行时期常量:jvm需要加载,引用类型都需要加载.

  5. 作用

    • 用来修饰一个引用

      如果引用为基本数据类型,则该引用为常量,该值无法修改;

      如果引用为引用数据类型,比如对象、数组,则该对象、数组本身可以修改,但指向该对象或数组的地址的引用不能修改。

      如果引用是类的成员变量,则必须当场赋值,否则编译会报错。

      在这里插入图片描述

    • 用来修饰一个方法

      当使用final修饰方法时,这个方法将成为最终方法,无法被子类重写。但是,该方法仍然可以被继承。

    • 用来修饰类

      当用final修饰类时,该类成为最终类,无法被继承。简称为“断子绝孙类”。

十一、this和super的区别

this:代表的当前类对象的地址值引用
super:代表父类的空间标识 (父类的对象的地址值引用)

使用不一样:
        this.变量名 : 访问本类的成员变量
        super.变量名: 访问父类的成员变量

        this.方法名() ;  访问本类的成员方法
        super.方法名(); 访问父类的成员方法

        this() :访问本类的无参构造方法
        super():访问父类的无参构造方法
        
        this(xx): 访问本类的有参构造方法
        super(xx):访问父类的有参构造方法

十二、 方法重写和方法重载的区别

  1. 方法重载Overload

    定义方法的时候,多个方法的方法名相同,参数列表不同,与返回值无关.

  2. 方法重写Override

    在继承中,子类出现了和父类一模一样的方法声明,子类会将父类的方法覆盖,使用子类自己的一些功能.重写的时候要保证访问权限足够大.

  3. Overload和Override没有关系

十三、多态

  1. 概念:

    能够体现事物的不同形态(程序中,内存变化)

  2. 向上转型

    父类名 对象名 = new 子类名();(向上转型)

  3. 向下转型

    子类名 对象名 = (子类名)父类引用;

  4. 多态的条件

    • 必须要有继承关系

    • 必须存在方法重写

    • 必须存在父类引用,指向子类对象

      父类名 对象名 = new 子类名();

  5. 多态的成员访问特点

    ​ 父类名 对象名 = new 子类名();(向上转型);

    • 成员变量:编译看左边,运行看左边
    • 成员方法:编译看左边,运行看右边(非静态,静态方法跟类有关,不算重写,不构成多态)
    • 构造方法:由于存在继承,构造方法在执行的时候,分层初始化,先是父类初始化,再是子类初始化。
  6. 多态的好处

    • 可以提高代码的拓展性
    • 可以提高代码的复用性
    • 可以提高代码的可维护性
  7. 多态的弊端

    • 无法访问子类的特有方法

    解决办法:向下转型

  8. 向下转型的弊端

    使用不当可能出现运行时异常java.lang.ClassException。

十四、abstract(抽象)

  1. 有抽象方法的类,一定是从抽象类。抽象类不一定有抽象方法。

  2. abstract的冲突

    • 不能和private一起用。private修饰的方法只能在本类使用,而abstract修饰的方法必须在子类重写。
    • 不能和final一起用。final修饰的方法/类(断子绝孙类),无法被重写与继承。
    • 不能和static一起用。static修饰的方法,不能算重写。
  3. 抽象方法:只有方法声明,无方法体

    public abstract void show();
    

    抽象方法及抽象类的特点:

    • 特点:

      1. 抽象类不能实例化(不能new 创建对象)

      2. 抽象类的子类如果也是抽象类,不能实例化,一定会提供最具体的子类,完成实例化,否则无意义。

      3. 抽象方法必须被子类重写

  4. 抽象类的成员特点:

    抽象类多态 格式: 抽象的父类名 对象名 = new 具体子类名();

    • 成员变量

      既可以是变量,也可以是常量

    • 成员方法

      既可以是抽象方法(强制重写),也可以是普通方法

    • 构造方法

      可以是无参,也可以是有参。

  5. 一个类没有任何的抽象方法,但是还是定义为抽象类,是为了不让外界直接创建对象。

十五、interface 接口

  1. 接口是一种特殊的抽象类

  2. 概念:一系列方法的声明,是一些方法特征的集合

  3. 命名:遵循大驼峰命名法

  4. 特点:

    • 接口的方法不能有方法体,只能是抽象方法。隐藏 public abstract 可以不写。

    • 接口不能实例化(创建对象)

    • 如果接口的实现类是一个抽象类(不能实例化),肯定有一个具体的实现类来进行实例化(new对象)

      接口多态: 接口名 对象名 = new 具体的子实现类();

  5. 接口的成员特点

    • 成员变量: 只能是常量,定义变量时,存在默认修饰符 public static final
    • 成员方法:只能是抽象方法,存在默认修饰符 public abstract
    • 构造方法:接口没有构造方法(接口不能实例化,自然也就没有构造方法)
  6. 接口和抽象类的区别

    • 成员的区别

      • 抽象类

        • 成员变量:可以是常量,也可以是变量
        • 成员方法:可以是抽象,也可以是非抽象
        • 构造方法:可以是有参,也可以是无参
      • 接口

        • 成员变量:只能是常量,默认修饰符 public static final
        • 成员方法:只能是抽象方法 默认修饰符 public abstract
        • 构造方法:没有构造方法
    • 关系的区别

      • 类与类:继承关系,只支持单继承
      • 类与接口:实现关系(implement)一个类在继承另一个类的同时,还可以实现多个接口
      • 接口与接口:继承关系 extends
    • 设计理念的区别

      • 抽象类不能实例化,核心设计理念:is a 的关系
      • 接口不能实例化,核心设计理念:like a的关系

十六、Package (包)

  1. 本质是文件夹(目录)
  2. 开发中,公司域名反写,多个包用.隔开
  3. 目的:为了维护代码结构

十七、权限修饰符

在这里插入图片描述

十八、形式参数问题

    • 具体类
      • 实际参数需要传递当前类对象
    • 抽象类
      • 实际参数需要传递抽象类的具体子类对象(抽象多态)
  1. 接口

    接口不能实例化,实际参数需要传递接口的子实现类对象(接口多态)

十九 、返回值问题

  1. 返回基本类型

  2. 引用类型

      • 具体类

        需要返回当前类的对象

      • 抽象类

        需要返回当前抽象类的子类对象

    • 接口

    • 数组

二十、类与类,类与接口、接口与接口的关系

  1. 类与类:只支持单继承,但是可以多层继承

  2. 类与接口:实现关系,一个类继承另一个类的同时,可以实现多个接口。

    public interface A {
    }
    
    interface B{
    }
    
    class A1 {
    }
    
    class B1 extends A1 implements A,B{
    }
    
  3. 接口与接口:不仅可以单继承,也可以多继承

    public interface A {
    }
    
    interface B{
        
    }
    
    interface C extends A,B{
        
    }
    

二十一、内部类

  1. 格式

    class Outer{
    	//成员内部类
    	class Inner{	
    	}
    	 
    	public void show(){
            //局部内部类
            class Inner1{        
            }
        }
    }
    
  2. 成员内部类可以访问外部类的成员,包括私有相关的。

  3. 成员内部类的访问方式

    • 间接访问

    • 直接访问

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

  4. 成员内部类 可以被static修饰

    • 静态的成员内部类只能访问,外部类的静态成员

    • 静态的成员内部类中无论是静态方法还是非静态方法:访问外部类的成员必须静态

    • 想直接通过外部类来访问静态成员内部类的成员信息,访问格式:

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

  5. 局部内部类

    1. 外部类和内部类无继承关系
    2. 可以访问外部类的成员,包括私有
    3. 访问方式:
    	1. 在内部类所在的方法中创建内部类对象,创建外部类对象调用成员方法即可
    	2. 匿名内部类访问
    
  6. 匿名内部类

    1. 格式
    	new 抽象类名或接口名(){
    		//重写方法
    	};
    	
    	new 抽象类名或接口名(){
    		//重写方法
    	}.方法名();
    	
    2. 匿名内部类的本质
    	继承了该抽象类,或实现了该接口的子类对象。
    3. 应用范围:在局部位置使用(方法定义中或者声明上)
    
    4. 当接口或抽象类中有多个抽象方法时,可以给匿名内部类命名。如eg1
    
    5. 可以解耦,不用创建接口或抽象类的子实现类对象。如eg1
    
    6. 开发中的应用
    	1. 使用匿名内部类替代,接口或抽象类的子实现类对象。如eg2
    

    eg1:

    interface A{
        void show();
        void show1();
    }
    
    class Outer{
        public void function(){
    
            //没有给匿名内部类命名是,如果有多个抽象方法,调用不方便
            new A(){
    
                @Override
                public void show() {
                    System.out.println("show");
                }
    
                @Override
                public void show1() {
                    System.out.println("show1");
                }
            }.show();
    
            new A(){
    
                @Override
                public void show() {
                    System.out.println("show");
                }
    
                @Override
                public void show1() {
                    System.out.println("show1");
                }
            }.show1();
    
    
            //改进:给匿名内部类命名,通过对象名调用
            A a = new A() {
                @Override
                public void show() {
                    System.out.println("show 命名匿名内部类");
                }
    
                @Override
                public void show1() {
                    System.out.println("show1 命名匿名内部类");
                }
            };
            a.show();
            a.show1();
        }
    }
    
    
    public class InnerClassDemo {
        public static void main(String[] args) {
            Outer outer = new Outer();
            outer.function();
        }
    }
    
    
    

eg2:

//抽象类
abstract class Person {
    public abstract void work();
}

//定义PersonDemo类
class PersonDemo {
    public void show(Person p) {//引用类型--抽象类---需要抽象类子类对象
        p.work();
    }
}

//定义一个类(具体类),继承Person
class Progammer extends Person {

    @Override
    public void work() {
        System.out.println("程序员日日夜夜敲代码...");
    }
}

//测试类
public class ArgsDemo {
    public static void main(String[] args) {
        //调用PersonDemo类里面的show方法
        PersonDemo pd = new PersonDemo();
        //Person p = new Person() ;//抽象类不能new
        //抽象类多态
        Person p = new Progammer();
        pd.show(p);
        System.out.println("--------------------------------------");
        //方式2:可以使用抽象类的匿名内部类
        /**
         * new 抽象类名(){
         *     重写方法
         * }
         */
        pd.show(new Person() {
            @Override
            public void work() {
                System.out.println("人都需要工作...");
            }
        });
    }
}

二十二、常用类

  1. Object类

    • getClass

      获取任意Java类型的字节码文件对象(返回值表示正在运行的那个类或者接口)

  2. Java中获取一个类的字节码文件的方式:

    • getClass方法
    • 类名.class
    • Class类中有一个静态方法forName(“包名.类名”)

二十三、instanceof

  1. 应用

    对象名 instanceof 对象名 判断前面对象名是否是后面类型的一种实例。

  2. 代码示例

    class Father{
    }
    
    class Child extends Father{
    }
    
    public class Main{
        public static void main(String[] args){
            Child child = new Child();
            System.out.println(child instanceof Father);
        }
    }
    

二十四、拓展

  1. com.dao dao= Data Access Object(数据访问对象) 数据库访问层(持久层)
  2. com.dao.impl 数据库连接实现
  3. com.service 业务访问层
  4. com.service.impl 业务实现
  5. com.commons/utils 存储通用工具类
  6. com.controller 前后端交互的代码(前端和;后端的中间层:连接层)

二十五、Lambda 表达式

  1. 简介

    ​ Lambda表达式是Java SE 8中一个重要的新特性。lambda表达式允许你通过表达式来代替功能接口。 lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块)。 Lambda 表达式(Lambda expression)可以看作是一个匿名函数,基于数学中的λ演算得名,也可称为闭包(Closure)

  2. 语法

    基本语法: (parameters) -> expression 或 (parameters) ->{ statements; }

    Lambda表达式由三部分组成:

    1. paramaters:类似方法中的形参列表,这里的参数是函数式接口里的参数。这里的参数类型可以明确的声明也可不声明而由JVM隐含的推断。另外当只有一个推断类型时可以省略掉圆括号。
    2. ->:可理解为“被用于”的意思
    3. 方法体:可以是表达式也可以代码块,是函数式接口里方法的实现。代码块可返回一个值或者什么都不反回,这里的代码块块等同于方法的方法体。如果是表达式,也可以返回一个值或者什么都不反回。
  3. 函数式接口定义:一个接口有且只有一个抽象方法

  4. 本质

    Lambda表达式本质是一个匿名函数,函数的方法是:返回值 方法名 参数列表 方法体。在,Lambda表达式中我们只需要关心:参数列表 方法体。

二十六、选择排序

  1. 原理:
    数组角标从0开始,将它对应元素依次和后面的元素比较,将小的往前放,第一次比较完毕.最小值就出现在最小索引处!依次这样比较,可以得到一个排好序的数组

  2. 时间复杂度:O(n^2)

  3. 空间复杂度:O(n^2)

  4. 稳定性:不稳定

    举例说明:序列58539.我们知道第一遍选择第1个元素“5”会和元素“3”交换,那么原序列中的两个相同元素“5”之间的前后相对顺序就发生了改变。因此,我们说选择排序不是稳定的排序算法,它在计算过程中会破坏稳定性。

  5. 代码实现

    import java.util.Arrays;
    
    public class Choice {
        public static void main(String[] args) {
            int[] arr = {4,3,2,1};
            Choice choice = new Choice();
            choice.choice(arr);
    
    
        }
        //选择排序
        public int[] choice(int[] arr){
            for (int i = 0; i < arr.length; i++) {
                for (int j = i+1; j < arr.length ; j++) {
                    if (arr[i]>arr[j]){
                        int temp = arr[i];
                        arr[i] = arr[j];
                        arr[j] = temp;
                    }
                }
                System.out.println("第"+(i+1)+"次比较的结果是:");
                System.out.println(Arrays.toString(arr));
            }
            return arr;
        }
    }
    

    运行效果:

    在这里插入图片描述

  6. 和冒泡排序的区别:

    1. 冒泡排序核心代码

      for (int i = 0; i < arr.length-1; i++) {
          for (int j = 0; j < arr.length-i-1; j++) {
              if (arr[j]>arr[j+1]){
                  int temp = arr[j];
                  arr[j] = arr[j+1];
                  arr[j+1] = temp;
              }
          }
      }
      
    2. 选择排序核心代码

      for (int i = 0; i < arr.length; i++) {
                  for (int j = i+1; j < arr.length ; j++) {
                      if (arr[i]>arr[j]){
                          int temp = arr[i];
                          arr[i] = arr[j];
                          arr[j] = temp;
                      }
                  }
            }
      

​ 比较:冒泡排序是重复地走访要排序的元素列,依次比较两个相邻的元素,而选择排序是依次和后面的元素比较

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值