看书笔记

关于基本数据类型

char类型可以跟short byte int long 直接进行运算
不同的基本数据类型在进行运算时,会自动提升为当前运算中位数最高的那一个
##关于循环:break
多重循环时,可以定义一个标识符来结束内层循环,标识符必须定义在循环之前,格式为:英文+: (demo:)
使用实例:
IMAGE
上面的运行结果为:
I的值为:0,j的值为:0
I的值为:0,j的值为:1
程序运行到break outer;时,会直接结束outer标签指定的循环,而不是结束break所在的循环,是结束break循环的外层循环,所以定义break后的标签时,通常是定义在break所在循环之外的外层循环处.
##continue
continue后面也可以接标签,定义方法同break,只不过continue后面标签的作用是跳过标识循环的当次循环的语句,直接开始下一次循环.

数组

数组初始化完成后,长度固定,且存储的数据类型是唯一的,数组本身也是一种数据类型,是引用数据类型,定义数组时,只是定义了一个引用变量,并没有指向任何有效内存,所以在定义时,不能指定数组长度,想要使用定义的数组,必须进行初始化.
数组没有初始化时,只是一个引用变量,一般存放在栈内存中,当初始化后,初始化的值是存放在堆内存中的,是栈内存的引用变量指向堆内存的初始化的值
IMAGE
如上图,最后输出b数组的长度为3,表面上看好像是b数组的长度改变了,其实不然,是b数组的引用变量指向了同类型的a数组的初始化的值,如下图
IMAGE
在程序运行时,会产生4块内存区,栈内存中两块分别存a,b两个引用变量,堆内存也有两块内存区,分别存a,b引用所指向的数组本身,当系统执行b=a时,是把a的值赋给了b.a,b又都是引用类型变量,给的是地址值,所以,b就指向了a,因此b的长度发生变化成为3

面向对象

关于static,类中的方法和变量通过static修饰后,可以直接通过类名.方法(变量)名来调用,这些方法和变量叫做静态方法(变量).
关于this,this通常代表了该类本身的对象,所以在java程序中,可以使用this来代替该类的对象,有两种使用情况:
1.构造器中引用该构造器正在初始化的对象.
2.在方法中引用调用该方法的对象.
对于static修饰的方法,可以直接通过类名来调用,但不能通过this来调用,个人见解:
1.this是指向的该类的对象,而调用static修饰的方法则是通过类名来调用的,所以会出现找不到指定的对象的异常.
2.static修饰的方法得在装载class的时候完成,比构造方法要早,而非static的属性和方法还没有完成初始化.
所以可以推出,静态的成员不能访问非静态的成员.
ps:java中允许使用对象来调用static修饰的成员变量,方法

##方法传递参数机制
是将实际参数的副本传入方法内,参数本身不会受到任何影响IMAGE
上图的运行结果swap方法里,a是9,b是6;交换结束后,a是6,b是9
在内存中的示意图如下:
IMAGE
当发生交换时,其实是swap栈区的a,b变量发生了交换.
IMAGE
原main栈区的内容是没有发生任何变化的.
再看下面这个例子:
IMAGE
结果如下:
IMAGE
这个例子跟上面的那个例子的区别是什么呢?它是通过对象来传递值的,而上一个是直接通过基本数据类型来传递值的,上一个产生的数据都会存在栈内存,而这一次产生的数据,引用变量存放在栈内存,而对象是产生在堆内存中的,所以,在代码执行的过程中就会出现如下情况:
IMAGE
main栈区和swap栈区存放的都只是引用变量,main栈区的dw存放的是DW对象的地址值,当swap方法执行时,swap传递的参数只是dw中的地址值,所以swap栈区的dw变量也是指向的是堆内存中的DW对象,所以指向的是同一个地方,swap中的变量发生变化时,DW中的对象也随之发生了变化,所以main栈区中的变量也会随之发生变化.
##关于局部变量和成员变量的初始化
定义一个person类,一个是实例变量,一个是类变量
IMAGE
接下来进行初始化
IMAGE
因为程序是第一次使用person类,所以会初始化,在堆内存为它分配内存空间,因为类变量是static修饰,所以会在类初始化的时候也会初始化.
IMAGE
当Person类初始化完成后,系统创建了一个person对象,对象里包含了name的实例变量,而类变量不属于创建的person对象,效果图如下:
IMAGE
实例变量进行赋值时没有什么需要注意的点,需要注意的点事类变量进行赋值的时候,当程序执行到p1.eyeNum=2时,是通过p1来访问Person的eyeNum类变量,修改的也是Person的eyeNum类变量.
具体的赋值过程如下图:
IMAGE

封装

隐藏该隐藏的,暴露该暴露的.需要使用访问控制符实现.
一共有4个访问级别,由小到大:
private->default->protected->public

继承

super关键字,super是用在子类调用父类继承得到的实例变量或者方法,super不能调用static修饰的方法中,因为static修饰的方法是属于类的,改方法的调用者是类,super是父类的对象,所以用super去调用static修饰的方法就没有了意义

多态

简单点说,就是类的编译时类型和运行时类型的不同,子类和父类,在编译时期,类对象是父类的类型,但运行时,父类调用子类的方法或者类变量,就形成了多态.
对象实例变量不具有多态性,

单例

一个类始终只能创建一个实例,这个类被称为单例类.
单例类Demo:
IMAGE

抽象类使用

抽象类多是作为抽象模板模式设计来使用:
IMAGE
IMAGE
如图,因为车轮半径不能确定,所以把定义半径的方法作为抽象方法,子类在继承抽象类,去实现父类的抽象方法,进而实现实时控制车轮的半径

接口

接口的继承可以实现多继承,接口中定义的常量,默认是由public static final 三个关键字修饰.
接口和抽象类的异同:
同:
1.接口和抽象类都不能实例化,都位于继承树的顶端,用于被其他类实现和继承.
2.接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法.
异:
主要体现在设计目的上:
1.接口体现的是一种规范,对于接口的实现者而言,接口规定了实现者必须向外提供哪些服务;对于调用者而言,接口规定了调用者可以调用哪些方法.当一个程序使用接口时,接口是多个模块间的耦合标准;当在多个应用程序之间时,接口是多个程序之间的通信标准.
2.抽象类则是一种模板设计,抽象类作为多个子类的抽象父类,可以被当成系统实现过程中的中间产品
方法上也有不同:
1.接口中只能包含抽象方法和默认方法,不能为普通方法提供方法实现;抽象类可以包含普通方法.
2.接口里不能定义静态方法;抽象类可以定义静态方法.
3.接口里只能定义静态常量,不能定义普通成员变量;抽象类里都可以定义.
4.接口里不包含构造器,抽象类可包含,并且作用是让子类调用完成抽象类的初始化.
5.接口不包含初始化块;抽象类可包含.
6.继承只能一个,接口可以实现多个.

面向接口编程

1.简单工厂模式Demo:

//先建一个接口
public interface Output {

    void out();
    void getData(String msg);
}
//再建一个printer类实现接口
public class Printer implements Output {
    @Override
    public void out() {
        System.out.println("out");
    }

    @Override
    public void getData(String msg) {
        System.out.println(msg);
    }
}
//接下来,建类包含最上面的接口
public class Computer {

    private Output output;
    //构造方法中包含接口
    public Computer (Output output){
        this.output=output;
    }
    //两个方法都调用接口自己的方法
    public void keyIn(String msg){
        output.getData(msg);
    }

    public void print(){
        output.out();
    }
}
//构建接口工厂
public class OutputFactory {
    //因为printer类实现了Out接口(多态)
    public Output getOutput(){
        return new Printer();
    }
    
    public static void main(String[] args) {
        OutputFactory outputFactory = new OutputFactory();
        Computer computer = new Computer(outputFactory.getOutput());
        computer.keyIn("hello");
        computer.print();
    }
}
//运行结果
hello
out

在上面的代码中,Computer类与printer完全分离,只与Output接口耦合,并且Output对象由定义的工厂来生成,这样就改变了整个代码的结构,如果把Computer类与printer类耦合,那么当要把printer换成别的类时,就会特别麻烦,但经过这样操作后,把Output定义成接口,接口里定义自己想要的方法,再去定义实体类来实现这个接口,让Computer类通过output来调用对应的实体类方法.而不再是直接调用实体类.通过接口来调用需要的实体类方法.
这种方式可以把所有生成output对象的逻辑集中在工厂类中管理,所有需要使用output对象的类只需与output接口耦合,不用与具体的实现类耦合
2.命令模式Demo:
应用场景:某个方法需要完成某一行为,但这个行为的具体实现无法确定,必须等到执行该方法时才可以确定,例如有个方法需要遍历某个人数组的数组元素,但无法确定在遍历数组元素时要如何处理这些元素,需要再调用方法时指定具体的处理行为.

//定义公共接口
public interface Command {

    void process(int [] target);
}
//两个不同的实现类
public class AddCommand implements Command {
    @Override
    public void process(int[] target) {
        int sum =0;
        for (int i : target) {
            sum+=i;
        }
        System.out.println("add方法输出"+sum);
    }
}
public class PrintCommand implements Command {
    @Override
    public void process(int[] target) {
        for (int i : target) {
            System.out.println("print方法输出"+i);
        }
    }
}
//调用
public class ProcessArray {
    public void process(int [] target,Command command){
        command.process(target);
    }

    public static void main(String[] args) {
        ProcessArray processArray = new ProcessArray();
        int []arr1={1,2,3,4};
        processArray.process(arr1,new PrintCommand());
        processArray.process(arr1,new AddCommand());

    }
}

在这个demo里,通过这种处理方式就可以实现process()方法和处理行为的分离.

内部类

内部类成员可以直接访问外部类的私有数据,但外部类不能访问内部类的实现细节.
内部类可以比外部类多用三个修饰符:private,protected,static,非静态内部类不能拥有静态成员.
内部类的使用场景:
1.在外部类内部使用内部类
与平常使用的普通类没有太大区别,可以直接通过内部类类名定义变量,通过new调用内部类构造器来创建实例
2.在外部类以外使用非静态内部类
如果内部类使用private修饰,那么该内部类只能在外部类的内部使用,
匿名内部类
IMAGE

Lambda表达式

上面有说到内部类,其实lambda表达式的使用的很重要的一个方面就是函数式接口,说白了其实就是创建一个只有一个抽象方法的接口的实例.其实就是内部类的引用
接下来用lambda表达式来改写之前的那个commond

public class ProcessArray {
    public void process(int [] target,Command command){
        command.process(target);
    }

    public static void main(String[] args) {
        ProcessArray processArray = new ProcessArray();
        int []arr1={1,2,3,4};
        processArray.process(arr1, target -> {
            for (int i : target) {
                System.out.println(i);
            }
        });

    }
}

lambda表达式的目标类型必须是函数式接口,并且这个函数式接口只能包含以一个抽象方法,用到lambda表达式的地方,当采用匿名内部类语法来创建函数式接口的实例,并且只有一个抽象方法要实现的时候,就可以用lambda表达式带来创建对象.
关于lambda表达式,lambda只能对于只有一个抽象方法的函数式接口创建对象.例如Runnable接口
Runnable接口只有一个run方法,没有参数,所以就可以通过lambda表达式来确定Runnable的对象.

 Runnable runnable = () -> {
            for (int i = 0; i < 10; i++) {
                System.out.println(i);
            }
        };
        runnable.run();

为了保证lambda表达式的目标类型是一个明确的函数式接口,可以有如下三种方式:
1.将lambda表达式赋值给函数式接口类型的变量.
2.将lambda表达式作为函数式接口类型的参数传给某个方法
3.使用函数式接口对lambda表达式进行强制类型转换.
java8最典型的4个函数式接口:
1.xxxFunction:这类接口中通常包含一个apply()抽象方法,该方法对参数进行处理,转换,然后返回一个新的值,该函数式接口通常用于对指定数据进行转换处理.
2.xxxConsumer:这类接口通常包含一个accept()抽象方法,该方法与上面的方法基本相似,也负责对参数进行处理,只是不会返回处理结果.
3.xxxPredicate:这类接口通常包含一个test()抽象方法,该方法通常用来对参数进行某种判断,然后返回一个boolean值,该接口通常用于判断参数是否满足特定条件,常用于进行数据的筛选.
xxxSupplier:这类接口通常包含一个getAsXxx()抽象方法,该方法不需要输入参数,该方法会按照某种逻辑算法,返回一个数据.

方法与构造器的引用

IMAGE
1.引用类方法demo:

//函数式接口
@FunctionalInterface
public interface Converter {
    //传一个字符传,返回一个int
    Integer convert(String from);
}
//输出2
public static void main(String[] args) {
        //演变过程2
        Converter converter2 = from -> Integer.valueOf(from);
    //演变过程1
    Converter converter1 = from -> {
        return Integer.valueOf(from);
    };
        //演变过程3
        Converter converter = Integer::valueOf;
        System.out.println(converter.convert("2"));
    }

定义这个函数式接口的时候,接口中的方法是需要返回一个int类型的值,传入的参数类型是一个string字符串,所以在实现的过程中,因为方法简单,只有一行代码所以省略掉{}和retrun,参数也只有一个,所以参数也可以省略,最终就变成了过程3
2.引用特定对象的实例方法
这个跟上面的基本一样,只是把类名替换成了具体的对象,所以省略demo.
3.引用某类对象的实例方法
demo:

//接口
@FunctionalInterface
public interface Converter {

    String convert(String a,int b,int c);
}
//具体实现
public static void main(String[] args) {
        //演变1
        Converter converter1 =(a,b,c)->{
           return a.substring(b,c);
        };
        //演变2
        Converter converter2 =(a,b,c)->a.substring(b,c);
        //演变3
        Converter converter3 =String::substring;

        System.out.println(converter3.convert("we have world",0,5));
    }
//输出结果
we have

这个看似和引用类的没有太大区别,唯一的区别就是在于类是把实现方法的全部参数作为入参传给接口,而引用类对象的则是把第一个参数作为调用者,后面的参数才是当参数用的
4.构造器引用
构造器很少用到,暂时不涉及

Lambda表达式与匿名内部类的异同

相同点:
1.都可以直接访问"effectively final"的局部变量,以及外部类的成员变量(类变量和实例变量).
2.都可以直接调用从接口中继承的默认方法.
不同点:
1.匿名内部类可以为任意接口创建实例,不管多少个抽象方法,但lambda表达式只能为函数式接口创建实例.
2.匿名内部类可以为抽象类和普通类创建实例,但lambda表达式只能为函数式接口创建实例.
3.匿名内部类实现的抽象方法的方法体允许调用接口中定义的默认方法;但lambda表达式的代码块不允许调用接口中定义的默认方法.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值