JAVA基础

未完成

重中之重:
https://www.cnblogs.com/strivers/p/6537620.html
https://blog.csdn.net/weixin_37766296/article/details/80467341
基本数据类型
*****java共有8种数据类型:字符型(char)、布尔型(boolean)、整数型(int、short、long、byte)、浮点型(float、double)

*****byte:1个字节,最大存储数据量是256,存放的数据范围是-128~127之间。
*****short:2个字节,最大数据存储量是65536,数据范围是-32768~32767之间。
*****int:4个字节,最大数据存储容量是2的32次方,数据范围是负的2的31次方到正的2的31次方减1。这是因为一个数在计算机中是以 补码形式存储的,对于负数来说,它的补码是去掉符号位的所有位取反之后加一。int是4个字节,32位,
10000000 00000000 00000000 00000000 是补码,第一位为符号位,1表示负数,所以
对剩下的位取反,结果为 1111111 11111111 11111111 11111111,加一后为10000000 00000000 00000000 00000000
所以原码指的是-2^31=-2147483648
int的取值范围为-231——231-1
*****long:8个字节,最大数据存储容量是2的64次方,数据范围为负的2的63次方到正的2的63次方减1,赋值时需要加l或者L。
*****float:4个字节,数据范围在3.4e-45~1.4e38,直接赋值时必须在数字后加上f或F,如果不加就默认为double类型。
*****double:8个字节,数据范围在4.9e-324~1.8e308,赋值时可以加d或D也可以不加。
*****boolean:1个字节,只有true和false两个取值。
*****char:2个字节,存储Unicode码,用单引号赋值。
在Java中,整数类型(byte/short/int/long)中,对于未声明数据类型的整形,其默认类型为int型。在浮点类型(float/double)中,对于未声明数据类型的浮点型,默认为double型。

基本类型byte 二进制位数:Byte.SIZE最小值:Byte.MIN_VALUE最大值:Byte.MAX_VALUE
基本类型short二进制位数:Short.SIZE最小值:Short.MIN_VALUE最大值:Short.MAX_VALUE
基本类型char二进制位数:Character.SIZE最小值:Character.MIN_VALUE最大值:Character.MAX_VALUE
基本类型double 二进制位数:Double.SIZE最小值:Double.MIN_VALUE最大值:Double.MAX_VALUE

数据类型的自动转换:当进行赋值时范围小的会自动转化为范围大的。

package com.corn.testcast;
public class TestCast {
    public static void main(String[] args) {
        byte p = 3; // 编译正确:int到byte编译过程中发生隐式类型转换
        int  a = 3;
        byte b = a; // 编译出错:cannot convert from int to byte
        byte c = (byte) a; // 编译正确
        float d = (float) 4.0;
    }
}
//b错误的原因是a是int型的3,虽然这个大小也在byte的范围中。但是在编译过程中,b被赋值的是变量a,事先不知道是否a的大小能在byte范围中。保险起见编译出错。

short s1 = 1; s1 = s1 + 1是错误的; short s1 = 1; s1 +=1是正确的

public class Test {
	public static void main(String[] args){
		int a = 2;
		float b = 6;
		a+=b; //right
//		a=a+b; //error
		a=(int) (a+b); //right
	}
}
//当使用a=a+b的时候,会抛出”Exception in thread "main" java.lang.Error: Unresolved compilation problem: Type mismatch: cannot convert from float to int“的异常,这是可以理解的,如果不使用(int)强制类型转换的话,float 是不能直接复值给int 变量的。
我们将a=a+b注释掉,javac编译完之后,再使用反编译软件(例如XJad)打开Test.class文件,会发现源代码被解析成这样子:
public class Test
{
	public Test()
	{
	}
	public static void main(String args[])
	{
		int a = 2;
		float b = 6F;
		a = (int)((float)a + b);
		a = (int)((float)a + b);
	}
}
//即a+=b进行了强制类型转换,和 a=(int)((float)a+b)是等价的!

存在使i + 1 < i的数吗()
答案:存在
解析:如果i为int型,那么当i为int能表示的最大整数时,i+1就溢出变成负数了,此时不就<i了吗。
扩展:存在使i > j || i <= j不成立的数吗()
答案:存在
解析:比如Double.NaN或Float.NaN(计算0/0或者负数的平方根为NaN。变量可以与它自身进行比较。 如果比较的结果不等,那么它就是 NaN 。 这是因为 NaN 是唯一与自身不等的值)
0.6332的数据类型是()
A float B double C Float D Double
答案:B
解析:默认为double型,如果为float型需要加上f显示说明,即0.6332f
八进制以0为前缀,十六进制以0x为前缀

包装类三种类型互相转换

/** 将int类型转换为Integer类型*/
int intNum = 10;
Integer integer = new Integer(intNum);
/** 将Integer类型转换为int类型*/
int intValue = integer.intValue();
//自动装箱有性能损耗,在循环中应避免。
//包装类型和基本类型用==比较的时,会发生拆箱
Integer a=128;
Integer b=128;
System.out.println("a==b : " + (a == b)); //false,不会自动拆箱,比较的是引用,不是同一个地址引用
System.out.println("a>b : " + (a > b)); // false,会自动拆箱
System.out.println("a<b : " + (a < b)); // false,会自动拆箱
//但是,由于 JVM 会缓存-128 到 127 的 Integer 对象,所以当包装类的值在-128 到 127 的范围内,判等比较的是同一个引用。
Integer a=127;
Integer b=127;
System.out.println("a==b : " + (a == b)); //true,是同一个地址引用
//那么对于 128 这样数字的包装类,判等该怎么做?很简单,手动拆箱,或者用 equals 方法。equals 方法会拆箱后,根据基本类型比较,所以比较的是两者值的大小。

//但是会出现问题
System.out.println("b.equals(c) : " + (b.equals(c))); //true
System.out.println("b.equals(d) : " + (b.equals(d))); //false
//因为基本类型会被自动装箱,放入 equals 方法,然后第一步会判等是否是 Integer 的类型,那么 long d 会被装箱成 Long,所以类型就不一致,直接不进行比较,返回 false。而 int c 会装箱成 Integer 而类型一致,可以继续比较下去。

总结:包装类是一个对象,基本类型不是。包装类和基本类型可以互相转换,转换的过程称之为装箱拆箱,可以手动转换,也可自动转换。包装类比较大小的时候有很多坑,比如: ==比较引用,Integer 类型只有在-128 到 127 的范围内,才会持有同一个引用。equals 方法会先比较类型是否一致,不一致直接 false。最佳的操作实践是,比较大小的时候,统一先手动拆箱,然后再比较值。
常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。除Float和Double以外, 其它六种都实现了常量池, 但是它们只在大于等于-128并且小于等于127时才使用常量池,超出此范围仍然会去创建新的对象。
比较方法总结:
1.如果有一边是基本类型,那比较的就是值
2.如果两边是对象,比较的是地址,如果是自动装箱生成的,那么在IntegerCache.low 到 IntegerCache.high的范围内是相等,因为是同个对象,超过这范围就会重新生成对象
3.如果一边有计算表达式,那么就是比较的值
引用数据类型
基本数据类型在被创建时,在栈上给其划分一块内存,将数值直接存储在栈上;引用数据类型在被创建时,首先要在栈上给其引用(句柄)分配一块内存,而对象的具体信息都存储在堆内存上,然后由栈上面的引用指向堆中对象的地址。
在内存中的具体创建过程是:
1.首先在栈内存中位其p分配一块空间;
2.在堆内存中为Person对象分配一块空间,并为其三个属性设初值"",0;
3.根据类Person中对属性的定义,为该对象的两个属性进行赋值操作;
4.调用构造方法,为两个属性赋值为"Tom",20;(注意这个时候p与Person对象之间还没有建立联系);
5.将Person对象在堆内存中的地址,赋值给栈中的p;通过句柄p可以找到堆中对象的具体信息
包括类、接口类型、枚举类型、注解类型、数组、lambda六种

关于引用数据类型在内存中的状态:https://zhuanlan.zhihu.com/p/28654272

Java数据的5种内存存储位置:
1、寄存器:这是最快的保存区域,因为它位于和其他所有保存方式不同的地方:处理器内部。然而,寄存器的数量十分有限,所以寄存器是根据需要由编译器分配。我们对此没有直接的控制权,也不可能在自己的程序里找到寄存器存在的任何踪迹。
2、栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中。
3、堆:存放用new产生的数据。
4、静态域:存放在对象中用static定义的静态成员。
5、常量池:存放常量。
6、非 RAM 存储:若数据完全独立于一个程序之外,则程序不运行时仍可存在, 并在程序的控制范围之外。 其中两个最主要的例子便是 “流式对象” 和 “固定对象” 。
string类型:

/** String的属性值 */  
    private final char value[];
    /** The offset is the first index of the storage that is used. */
    /**数组被使用的开始位置**/
    private final int offset;
    /** The count is the number of characters in the String. */
    /**String中元素的个数**/
    private final int count;
    /** Cache the hash code for the string */
   /**String类型的hash值**/
    private int hash; // Default to 0
    /** use serialVersionUID from JDK 1.0.2 for interoperability */
    private static final long serialVersionUID = -6849794470754667710L;
    /**
     * Class String is special cased within the Serialization Stream         Protocol.
     * A String instance is written into an ObjectOutputStream according to
     * <a href="{@docRoot}/../platform/serialization/spec/output.html">
     * Object Serialization Specification, Section 6.2, "Stream Elements"</a>
     */
  private static final ObjectStreamField[] serialPersistentFields =
        new ObjectStreamField[0];
String的成员变量
//从源码看出String底层使用一个字符数组来维护的。成员变量可以知道String类的值是final类型的,不能被改变的,所以只要一个值改变就会生成一个新的String类型对象,存储String数据也不一定从数组的第0个元素开始的,而是从offset所指的元素开始。
String str="hello";//直接赋值的方式,直接赋值方式创建对象是在方法区的常量池
String str=new String("hello");//实例化的方式,通过构造方法创建字符串对象是在堆内存
//两种实例化方式的区别
 1)直接赋值(String str = "hello"):只开辟一块堆内存空间,并且会自动入池,不会产生垃圾。
 2)构造方法(String str=  new String("hello");:会开辟两块堆内存空间,其中一块堆内存会变成垃圾被系统回收,而且不能够自动入池,需要通过public  String intern();方法进行手工入池。在开发的过程中不会采用构造方法进行字符串的实例化。
public class Apple {
    public static void main(String[] args) {
        String a = "abc";
        String b = "abc";
        String c = new String("abc");
        System.out.println(a==b);  //true
        System.out.println(a.equals(b));  //true
        System.out.println(a==c);  //false
        System.out.println(a.equals(c));  //true,在object中,equals()是用来比较内存地址的,但是String重写了equals()方法,用来比较内容的,即使是不同地址,只要内容一致,也会返回true,这也就是为什么a.equals(c)返回true的原因了。亨元模式:其实字符串常量池这个问题涉及到一个设计模式,叫“享元模式”,顾名思义 - - - > 共享元素模式。也就是说:一个系统中如果有多处用到了相同的一个元素,那么我们应该只存储一份此元素,而让所有地方都引用这一个元素,Java中String部分就是根据享元模式设计的,而那个存储元素的地方就叫做“字符串常量池 - String Pool”
    }
}

BigDecimal:
Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数,但在实际应用中,可能需要对更大或者更小的数进行运算和处理。一般情况下,对于那些不需要准确计算精度的数字,我们可以直接使用Float和Double处理,但是Double.valueOf(String) 和Float.valueOf(String)会丢失精度。所以开发中,如果我们需要精确计算的结果,则必须使用BigDecimal类来操作。
BigDecimal所创建的是对象,故我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。

BigDecimal a =new BigDecimal(0.1);
System.out.println("a values is:"+a);
System.out.println("=====================");
BigDecimal b =new BigDecimal("0.1");
System.out.println("b values is:"+b);
//
a values is:0.1000000000000000055511151231257827021181583404541015625
=====================
b values is:0.1
//这是因为0.1无法准确地表示为 double(或者说对于该情况,不能表示为任何有限长度的二进制小数)。这样,传入到构造方法的值不会正好等于 0.1.
//String 构造方法是完全可预知的:写入 newBigDecimal(“0.1”) 将创建一个 BigDecimal,它正好等于预期的 0.1。因此,比较而言, 通常建议优先使用String构造方法。
//
add(BigDecimal)
BigDecimal对象中的值相加,返回BigDecimal对象
subtract(BigDecimal)
BigDecimal对象中的值相减,返回BigDecimal对象
multiply(BigDecimal)
BigDecimal对象中的值相乘,返回BigDecimal对象
divide(BigDecimal)
BigDecimal对象中的值相除,返回BigDecimal对象

java当中的四种引用:强引用,软引用,弱引用,虚引用:https://juejin.im/post/5b82c02df265da436152f5ad

包装类底层实现,枚举类
常量
定义常量有三种方式:
方法一采用接口(Interface)的中变量默认为static final的特性。
方法二采用了Java 5.0中引入的Enum类型。
方法三采用了在普通类中使用static final修饰变量的方法。
运算符与流程控制
switch中能否使用string做参数:
switch可作用于char byte short int string
switch可作用于char byte short int对应的包装类
switch不可作用于long double float boolean,包括他们的包装类
String s1=”ab”, String s2=”a”+”b”, String s3=”a”, String s4=”b”, s5=s3+s4请问s5==s2返回什么?
返回false。在编译过程中,编译器会将s2直接优化为”ab”,会将其放置在常量池当中,s5则是被创建在堆区,相当于s5=new String(“ab”);

//你对String对象的intern()熟悉么?intern()方法会首先从常量池中查找是否存在该常量值,如果常量池中不存在则现在常量池中创建,如果//已经存在则直接返回。
String s1=”aa”; 
String s2=s1.intern(); 
System.out.print(s1==s2);//返回true

对象与引用
创建对象的几种方式
采用new
通过反射
采用clone
通过序列化机制
成员变量、局部变量、静态变量
成员变量和局部变量的区别
成员变量:
①成员变量定义在类中,在整个类中都可以被访问。
②成员变量随着对象的建立而建立,随着对象的消失而消失,存在于对象所在的堆内存中。
③成员变量有默认初始化值。
局部变量:
①局部变量只定义在局部范围内,如:函数内,语句内等,只在所属的区域有效。
②局部变量存在于栈内存中,作用的范围结束,变量空间会自动释放。
③局部变量没有默认初始化值
成员变量和静态变量的区别
1、两个变量的生命周期不同
成员变量随着对象的创建而存在,随着对象被回收而释放。
静态变量随着类的加载而存在,随着类的消失而消失。
2、调用方式不同
成员变量只能被对象调用。
静态变量可以被对象调用,还可以被类名调用。
3、别名不同
成员变量也称为实例变量。
静态变量也称为类变量。
4、数据存储位置不同
成员变量存储在堆内存的对象中,所以也叫对象的特有数据。
静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。
在这里插入图片描述
private、protected、public
匿名对象
java集合
静态关键字static
this与super
抽象方法与抽象类
抽象类可以有方法实现。 抽象类可以有非final成员变量。 抽象方法要用abstract修饰。 抽象类可以有构造方法,但是只能由子类进行实例化。
接口可以用extends加多个接口实现多继承。 接口只能有public final类型的成员变量。 接口只能有抽象方法,不能有方法体、 接口不能实例化,但是可以作为引用类型。
接口
Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能)。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须宣告为抽象类(Abstract Class)。其中一个使用接口的优势是,可以利用他们模拟多重继承,类在JAVA中不允许多重继承,所有在JAVA中的类必须而且仅能有一个父类。Java接口的方法只能是抽象的和公开的,Java接口不能有构造器,Java接口可以有public、静态的和final属性。

interface 接口名称{
    全局常量;
    抽象方法;
}

使用接口的好处:可以实现多继承,提供规范
final关键字
final修饰基本数据类型保证不可变
final修饰引用保证引用不能指向别的对象,否则会报错。
final修饰类,类的实例分配空间后地址不可变,子类不能重写所有父类方法。因此在cglib动态代理中,不能为一个类的final修饰的函数做代理,因为cglib要将被代理的类设置为父类,然后再生成字节码。
final修饰方法,子类不能重写该方法。
成员内部类、匿名内部类、局部内部类
Java项目一般从src目录开始有com…A.java这样的目录结构。这就是包结构。所以一般编译后的结构是跟包结构一模一样的,这样的结构保证了import时能找到正确的class引用包访问权限就是指同包下的类可见。
import 一般加上全路径,并且使用.时只包含当前目录的所有类文件,不包括子目录。
外部类只有public和default两种修饰,要么全局可访问,要么包内可访问。
内部类可以有全部访问权限,因为它的概念就是一个成员变量,所以访问权限设置与一般的成员变量相同。
非静态内部类是外部类的一个成员变量,只跟外部类的实例有关。
静态内部类是独立于外部类存在的一个类,与外部类实例无关,可以通过外部类.内部类直接获取Class类型。
stringbuffer、stringbuilder
相同之处:
1、都继成了AbstractStringBuilder这个抽象类,实现了CharSequence接口
2、其append方法都是 super.append(str),调用了父类AbstractStringBuilder的append(String str)方法
3、初始容量都是16和扩容机制都是"旧容量
2+2"
4、底层都是用char[]字符数组实现,且字符数组都是可变的,这点不同于String
String:
在这里插入图片描述
final修饰的String 类,以及final修饰的char[] value,表示String类不可被继承,且value只能被初始化一次。这里的value变量其实就是存储了String字符串中的所有字符。在substring方法中,如果传入的参数为0,就返回自身原对象,否则就是重新创建一个新的对象。类似的,String类的concat方法,replace方法,都是内部重新生成一个String对象的。这也就是为什么我们如果采用String对象频繁的进行拼接,截取,替换操作效率很低下的原因。
StringBuilder:
在这里插入图片描述由final修饰,不可继承。空参构造方法默认初始字符数组大小为16;以字符串String 作为参数的构造,在参数Str 数组长度的基础上再增加16个字符长度,作为StringBuilder实例的初始数组容量,并将str字符串 append到StringBuilder的数组中。

public AbstractStringBuilder append(String str) {
    if (str == null)
        return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}
private void ensureCapacityInternal(int minimumCapacity) {
    // overflow-conscious code
    if (minimumCapacity - value.length > 0) {
        value = Arrays.copyOf(value,
                newCapacity(minimumCapacity));
    }
}
private int newCapacity(int minCapacity) {
    // overflow-conscious code
    int newCapacity = (value.length << 1) + 2;
    if (newCapacity - minCapacity < 0) {
        newCapacity = minCapacity;
    }
    return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
        ? hugeCapacity(minCapacity)
        : newCapacity;
}

在这里插入图片描述
StringBuffer:
在这里插入图片描述StringBuffer上使用了synchronized 关键字加了同步锁证明它是线程安全的,由final修饰,不可继承
Iterator接口
迭代器(Iterator)是一个对象,它的工作是遍历并选择序列中的对象。它提供了一种访问一个容器(container)对象中的各个元素,而又不必暴露该对象内部细节的方法。通过迭代器,开发人员不需要了解容器底层的结构,就可以实现对容器的遍历。由于创建迭代器的代价小,因此迭代器通常被称为轻量级的容器。

boolean hasNext():判断是否还有元素,如果仍有元素,返回true
E next():返回迭代的下一个元素,如果没有元素可以获取,则返回NoSuchElementException
	Iterator和ListIterator的区别:
	Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。
	Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。
	ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。
public Iterator<E> iterator() {//Iterator源码
        return new Itr();
    }
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;
        public boolean hasNext() {
            return cursor != size;
        }
        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();
            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
        @Override
        @SuppressWarnings("unchecked")
        public void forEachRemaining(Consumer<? super E> consumer) {
            Objects.requireNonNull(consumer);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i >= size) {
                return;
            }
            final Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length) {
                throw new ConcurrentModificationException();
            }
            while (i != size && modCount == expectedModCount) {
                consumer.accept((E) elementData[i++]);
            }
            // update once at end of iteration to reduce heap write traffic
            cursor = i;
            lastRet = i - 1;
            checkForComodification();
        }
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
for (Integer i : list) {
       System.out.println(i);
}
//反编译后
Integer i;
for(Iterator iterator = list.iterator(); iterator.hasNext(); System.out.println(i)){
        i = (Integer)iterator.next();        
}//其实增强for循环也是靠迭代器实现的
//迭代器的实现流程
public interface Collection {//1.首先定义一个容器Collection接口
 void add(Object o);
 int size();
 Iterator iterator();
}
public interface Iterator {//2.定义一个Iterator迭代器的接口
 Object next();
 boolean hasNext();
}
public class ArrayList implements Collection {//3.定义一个ArrayList,实现Collection接口,并写一个实现了Iterator接口的内部类
 Object[] objects = new Object[10];
 int index = 0;
 public void add(Object o) {
  if(index == objects.length) {
   Object[] newObjects = new Object[objects.length * 2];
   System.arraycopy(objects, 0, newObjects, 0, objects.length);
   objects = newObjects;
  }
  objects[index] = o;
  index ++;
 }
 public int size() {
  return index;
 }
 public Iterator iterator() {
  return new ArrayListIterator();
 }
 private class ArrayListIterator implements Iterator {
  private int currentIndex = 0;
  @Override
  public boolean hasNext() {
   if(currentIndex >= index) return false;
   else return true;
  }
  @Override
  public Object next() {
   Object o = objects[currentIndex];
   currentIndex ++;
   return o;
  }
 }
}
public class TestMain {//测试类
 public static void main(String[] args) {
  Collection c = new ArrayList();
  for(int i=0; i<15; i++) {
   c.add("string "+i);
  }
  System.out.println(c.size());
  Iterator it = c.iterator();
  while(it.hasNext()) {
   Object o = it.next();
   System.out.println(o.toString() + " ");
  }
 }
}

在这里插入图片描述在这里插入图片描述
当使用Iterator迭代器时,如果调用集合的remove()方法删除元素,或者调用add()方法添加元素,都会引发异常。原因是增删集合中的元素会导致预期的迭代次数无效,从而执行后抛出异常。该方法只能在每次调用next后调用一次。 如果底层集合已被修改而迭代器正在进程中(除了调用本方法),则迭代器的行为不能确定。 解决方法:使用Iterator迭代器自身的删除方法
看一下JDK中的集合类,比如List一族或者Set一族,都是实现了Iterable接口,但并不直接实现Iterator接口。 仔细想一下这么做是有道理的。因为Iterator接口的核心方法next()或者hasNext() 是依赖于迭代器的当前迭代位置的。 如果Collection直接实现Iterator接口,势必导致集合对象中包含当前迭代位置的数据(指针)。 当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。 除非再为Iterator接口添加一个reset()方法,用来重置当前迭代位置。 但即时这样,Collection也只能同时存在一个当前迭代位置。 而Iterable则不然,每次调用都会返回一个从头开始计数的迭代器。 多个迭代器是互不干扰的。
泛型
Java中的泛型是伪泛型,只在编译期生效,运行期自动进行泛型擦除,将泛型替换为实际上传入的类型。
泛型类用classA {
}
这样的形式表示,里面的方法和成员变量都可以用T来表示类型。泛型接口也是类似的,不过泛型类实现泛型接口时可以选择注入实际类型或者是继续使用泛型。
泛型方法可以自带泛型比如void go();
泛型可以使用?通配符进行泛化 Object可以接受任何类型
也可以使用 这种方式进行上下边界的限制。
lambda表达式(没看懂)
https://juejin.im/post/5abc9ccc6fb9a028d6643eea
https://objcoding.com/2019/03/04/lambda/

// JDK7 匿名内部类写法
new Thread(new Runnable(){// 接口名
	@Override
	public void run(){// 方法名
		System.out.println("Thread run()");
	}
}).start();
// JDK8 Lambda表达式写法
new Thread(
		() -> System.out.println("Thread run()")// 省略接口名和方法名
).start();
// JDK8 Lambda表达式代码块写法
new Thread(
        () -> {
            System.out.print("Hello");
            System.out.println(" Hoolee");
        }
).start();
// JDK7 匿名内部类写法
List<String> list = Arrays.asList("I", "love", "you", "too");
Collections.sort(list, new Comparator<String>(){// 接口名
    @Override
    public int compare(String s1, String s2){// 方法名
        if(s1 == null)
            return -1;
        if(s2 == null)
            return 1;
        return s1.length()-s2.length();
    }
});
// JDK8 Lambda表达式写法
List<String> list = Arrays.asList("I", "love", "you", "too");
Collections.sort(list, (s1, s2) ->{// 省略参数表的类型
    if(s1 == null)
        return -1;
    if(s2 == null)
        return 1;
    return s1.length()-s2.length();
});

面向对象三大特性
继承:一般类只能单继承,内部类实现多继承,接口可以多继承
封装:访问权限控制public > protected > 包 > private 内部类也是一种封装
多态:编译时多态,体现在向上转型和向下转型,通过引用类型判断调用哪个方法(静态分派)。
运行时多态,体现在同名函数通过不同参数实现多种方法(动态分派)。
序列化
Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。将序列化对象写入文件之后,可以从文件中读取出来,并且对它进行反序列化,也就是说,对象的类型信息、对象的数据,还有对象中的数据类型可以用来在内存中新建对象。
Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象。Java对象序列化就能够帮助我们实现该功能。
序列化:将对象写入到IO流中
反序列化:从IO流中恢复对象
意义:序列化机制允许将实现序列化的Java对象转换位字节序列,这些字节序列可以保存在磁盘上,或通过网络传输,以达到以后恢复成原来的对象。序列化机制使得对象可以脱离程序的运行而独立存在。
使用场景:所有可在网络上传输的对象都必须是可序列化的,比如RMI(remote method invoke,即远程方法调用),传入的参数或返回的对象都是可序列化的,否则会出错;所有需要保存到磁盘的java对象都必须是可序列化的。通常建议:程序创建的每个JavaBean类都实现Serializeable接口。

public class Employee implements Serializable//创建一个对象实现Serializable接口
{
   public String name;
   public String address;
   public transient int SSN;
   public int number;
   public void mailCheck()
   {
      System.out.println("Mailing a check to " + name
                           + " " + address);
   }
}
public class SerializeDemo
{
   public static void main(String [] args)
   {
      Employee e = new Employee();
      e.name = "Reyan Ali";
      e.address = "Phokka Kuan, Ambehta Peer";
      e.SSN = 11122333;
      e.number = 101;
      try
      {
         FileOutputStream fileOut =
         new FileOutputStream("/tmp/employee.ser");
         ObjectOutputStream out = new ObjectOutputStream(fileOut);
         out.writeObject(e);
         out.close();
         fileOut.close();
         System.out.printf("Serialized data is saved in /tmp/employee.ser");
      }catch(IOException i)
      {
          i.printStackTrace();
      }
   }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值