第五章面向对象(下)

5.1 Java 8 增强的包装类

把字符串类型的值转换为基本类型的值有两种方式。

  • 利用包装类提供的parseXxx(String s)静态(除了Character之外的所有包装类都提供了该方法)。
  • 利用包装类提供的Xxx(String s)构造器

String类提供了多个重载valueOf()方法,用于将基本类型变量转换成字符串,下面程序示范了这种各类型转换关系。

public class Student{public static void main(String[] args) {String intStr = "123";//把一个特定字符串转换成int变量int it1 = Integer.parseInt(intStr);int it2 = new Integer(intStr);System.out.println(it2);String floatStr = "4.56";//把一个特定字符串转换成float变量float ft1 = Float.parseFloat(floatStr);float ft2 = new Float(floatStr);System.out.println(ft2);//把一个double变量转换成String变量String dbStr = String.valueOf(3.344);System.out.println(dbStr);//把一个boolean变量转换成String变量String boolStr = String.valueOf(true);System.out.println(boolStr);}
}

Java8为Integer、Long增加了如下方法。

  • static String toUnsignedString(int/long i):该方法将指定int或long行整数转换为无符号整数对应的字符串。
  • static String toUnsignedString(int i/long, int radix):该方法将指定int或long型整数转换为指定进制的无符号整数对应的字符串。
  • static xxx pareUnsignedXxx(String s):该方法将指定字符串解析成无符号整数。当调用类为Integer时,xxx代表int;当调用类是Long时,xxx代表long。
  • static xxx parseUnsignedXxx(String s, int redix):该方法将指定字符串按指定进制解析成无符号整数。当调用类为Integer时,xxx代表int;当调用类时Long时,xxx代表long。
  • static int compareUnsigned(xxx x, xxx y):该方法将x、y两个整数转换为无符号整数后比较大小。当调用类为Integer时,xxx代表int;当调用类是Long时,xxx代表long。
  • static long divideUnsigned(long dividend, long divisor):该方法将x、y两个整数转换为无符号整数后计算它们相除的商。当调用类为Integer时,xxx代表int;当调用类时Long时,xxx代表long。

5.2 处理对象

5.2.1 打印对象和toString方法

object类提供的toString()方法总是返回该对象实现类的“类名+@+hashCode”值,这个返回值并不能真正实现“自我描述”的功能,因此如果用户需要自定义类能实现“自我描述”的功能,就必须重写Object类的toString()方法。例如下面程序。

class Apple{private String color;private double weight;public Apple(){}//提供没有参数的构造器public Apple(String color, double weight){this.color = color;this.weight = weight;}//省略color、weight的setter和getter方法...//重写toString()方法,用于实现Apple对象的“自我描述”public String toString(){return "一个苹果,颜色是:" + color+ ",重量是:" + weight;}
}
public class ToStringTest{public static void main(String[] args) {Apple a = new Apple("红色", 5.68);//打印Apple对象System.out.println(a);}

5.2.2 ==和equals方法

通常而言,正确地重写equals()方法应该满足下列条件

  • 自反性:对任意x,x.equals(x)一定返回true。
  • 对称性:对任意x和y,如果y.equals(x)返回true,则x.equals(y)也返回true。
  • 传递性:对任意x,y,z,如果x.equals(y),true y.equals(z)返回true,则x.equals(z)一定返回true。
  • 一致性:对任意x和y,如果对象中用于等价比较的信息没有改变,那么无调用x.equals(z)多少次,返回的结果应该保持一致,要么一直是true,要么一直是false。
  • 对任何不是null的x,x.equals(null)一定返回false。

Object默认提供的equals()只是比较对象的地址,即Object类的equals()方法比较的结果与==运算符比较的结果完全相同。因此在实际应用中常常需要重写equals()方法,重写equals方法时,相等条件时由业务要求决定的,因此equals()方法的实现也是由业务要求决定的。

5.3 类成员

static关键字修饰的成员就是类成员。

5.3.1 理解类成员

5.3.2 单例(Singleton)类

如果一个类始终只能创建一个实例,则这个类被称为单例类。
根据良好封装的原则:一旦把该类的构造器隐藏起来,就需要提供一个public方法作为该类的访问点,用于创建该类的对象,且该方法必须使用static修饰(因为调用该方法之前还不存在对象,因此调用该方法的不可能是对象,只能是类)。
除此之外,该类还必须缓存已经创建的对象,否则该类无法知道是否曾经创建过对象,也就无法保证之创建一个对象。为此该类需要使用一个成员变量来保存曾经创建的对象,因为该成员变量需要被上面的静态方法访问,故成员变量必须使用static修饰。
基于上面的介绍,下面程序创建了一个单例类。

class Singleton{//使用一个类变量来缓存曾经创建的实例private static Singleton instance;//对构造器使用private修饰,隐藏该构造器private Singleton(){}//提供一个静态方法,用于返回Singletion实例//该方法可以加入自定义控制,保证只产生一个Singleton对象public static Singleton getInstance(){//如果instance为null,则表明还不曾创建Singleton对象//如果instance不为null,则表明已经创建了Singletion对象//将不会重新创建新的实例if (instance == null){instance = new Singleton();}return instance;}
}
public class Student {public static void main(String[] args) {//创建Singleton对象不能通过构造器//只能通过geInstance方法来得到实例Singleton s1 = Singleton.getInstance();Singleton s2 = Singleton.getInstance();System.out.println(s1 == s2);//将输出true}
}

5.4 final修饰符

final关键字可用于修饰类、成员变量和方法,final关键字有点类似C#里面的sealed关键字,用于表示它修饰的类、方法和变量不可变。

5.4.1 final成员变量

对于final修饰的成员变量而言,一旦有了初始值,就不能被重新赋值,如果既没有在定义成员变量时指定初始值,也没有在初始化块、构造器中为成员变量指定初始值,那么这些成员变量的值将一直时系统默认分配的0、’\u0000’、false或null,这些成员变量也就完全失去了存在的意义。因此Java语法规定:final修饰的成员变量必须由程序员显式地指定初始值。
归纳起来,final修饰的类变量、实例变量能指定初始值的地方如下:

  • 类变量:必须在静态初始化块中指定初始值或声明该类变量时指定初始值,而且只能在两个地方的其中之一指定。
  • 实例变量:必须在非静态初始化块、声明该实例变量或构造器中指定初始值,而且只能在三个地方的其中之一指定。

5.4.2 final局部变量

系统不会对局部变量进行初始化,局部变量必须由程序员显式初始化。因此使用final修饰局部变量时,既可以在定义时指定默认值,也可以不指定默认值。
如果final修饰的局部变量在定义时没有指定默认值,则可以在后面代码中对该final变量赋初始值,但只能一次,不能重复赋值:如果final修饰的局部变量在定义时已经制定默认值,则后面代码中不能再对该变量赋值。

public class Student {public void test(final int a){//不能对final修饰的形参赋值,下面语法非法// a = 5}public static void main(String[] args) {//定义final局部变量时指定默认值,则str变量无法重新赋值final String str = "hello";//下面赋值语句非法//str = "Java";//定义final局部变量时没有指定默认值,则d变量可被赋值一次final double d;//第一次赋初始值,成功d = 5.6;// 对final变量重复赋值。下面语句非法// d = 3.4;}
}

5.4.3 final修饰基本类型变量和引用类型变量的区别

import java.util.Arrays;class Person{private int age;public Person(){}public Person(int age){this.age = age;}//省略age的setter和getter方法...
}
public class Student {public static void main(String[] args) {//final修饰数组变量,iArr时一个引用变量final int[] iArr = {5, 6, 12, 9};System.out.println(Arrays.toString(iArr));//对数组元素进行排序,合法Arrays.sort(iArr);System.out.println(Arrays.toString(iArr));//对数组元素赋值,合法iArr[2] = -8;System.out.println(Arrays.toString(iArr));//下面语句对iArr重新赋值,非法// iArr = null;// final修饰Person变量,p是一个引用变量final Person p = new Person(45);//改变Person对象的age实例变量,合法p.setAge(23);System.out.println(p.getAge());//下面语句对p重新赋值,非法// p = null;}
}

5.4.4 可执行“宏替换”的final变量

对于一个final变量来说,不管它是类变量、实例变量,还是局部变量,只要该变量满足三个条件,这个final变量就不再是一个变量,而是相当于一个直接量。

  • 使用final修饰符修饰。
  • 在定义该final变量时制定了初始值。
  • 该初始值可以在编译时就被确定下来。

5.4.5 final方法

final修饰的方法不可被重写,如果出于某些原因,不希望子类重写父类的某个方法,则可以使用final修饰该方法。

5.4.6 final 类

final修饰的类不可以有子类。

5.5 抽象类

5.5.1 抽象方法和抽象类

抽象方法和抽象类必须使用abstract修饰符定义,有抽象方法的类只能被定义成抽象类,抽象类里面可以没有抽象方法。
抽象方法和抽象类的规则如下:

  • 抽象类必须使用abstract修饰符来修饰,抽象方法也必须由abstract修饰符来修饰,抽象方法不能有方法体。
  • 抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。即使抽象类里面不包含抽象方法,这个抽象类也不能创建实例。
  • 抽象类可以包含成员变量、方法(普通方法和抽象方法都可以)、构造器、初始化块、内部类(接口、枚举)5种成分。抽象类的构造器不能用于创建实例,主要是用于被其子类调用。
  • 含有抽象方法的类(包括直接定义了一个抽象方法;或继承了一个抽象父类,但没有完全实现父类包含的抽象方法;或实现了一个接口,但没有完全实现接口包含的抽象方法三种情况)只能被定义成抽象类。

5.5.2 抽象类的作用

抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会大致保留抽象类的行为方式。

5.6 Java 8 改进的接口

5.6.1 接口的概念

5.6.2 Java 8 中接口的定义

和类定义不同,定义接口不再使用class关键字,而是使用interface关键字。定义接口的基本语法格式如下:

[修饰符] interface 接口名 extends 父接口1,父接口2...
{零个到多个常量定义...零个到多个抽象方法定义...零个到多个内部类、接口、枚举定义...零个到多个默认方法或类方法定义...
}

对上面语句的详细说明如下。

  • 修饰符可以时public或者省略,如果省略了public访问控制符,则默认采用包权限访问控制符,即只有在相同包结构下才可以访问该接口。
  • 接口名应与类名采用相同的命名规则,即如果仅从语法角度看,即接口名只要是合法的标识符即可;如果要遵循Java可读性规范,则接口名应由多个有意义的单词连缀而成。每个单词首字母大写,单词与单词之间无需任何分隔符。接口名通常能够使用形容词。
  • 一个接口可以有多个直接父类,但接口只能继承接口,不能继承类。

下面定义一个接口

package lee;
public interface Output{//接口里定义的成员变量只能是常量int MAX_CACHE_LINE = 50;//接口里定义的普通方法只能是public的抽象方法void out();void getData(String... msgs);//在接口中定义默认方法,需要使用default修饰default void print(String... msgs){for (String msg : msgs){System.out.println(msg);}}//在接口中定义默认方法,需要使用default修饰default void test(){System.out.println("默认的test()方法");}//在接口中定义类方法,需要使用static修饰static String staticTest(){return "接口里的方法";}
}

5.6.3 接口的继承

接口的继承和类的继承不一样,接口完全支持多继承,即一个接口可以有多个直接父类。和类继承相似,子接口扩展某个父接口,将会获得里定义的所有抽象方法、常量。

5.6.4 使用接口

归纳起来,接口主要有如下用途。

  • 定义变量,也可用于进行强制类型转换。
  • 调用接口中定义的常量。
  • 被其它类实现。

类实现接口的语法格式如下。

[修饰符] class 类名 extends 父类 implements 接口1,接口2...
{类体部分
}

5.6.5 接口和抽象类

接口和抽象类很像,它们都具有如下特征。

  • 接口和抽象类都不能被实例化,它们都位于继承树的顶端,用于被其它类实现和继承。
  • 接口和抽象类都可以包含抽象方法,实现接口或继承抽象类的普通子类都必须实现这些抽象方法。
    接口和抽象类在用法上也存在如下差别。
  • 接口里只能包含抽象方法、静态方法和默认方法不能为普通方法提供方法实现了;抽象类则完全可以包含普通方法。
  • 接口里只能定义静态常量,不能定义普通成员变量;抽象类里则既可以定义普通成员变量,也可以定义静态常量。
  • 接口里不包含构造器;抽象类里可以包含构造器,抽象类里的构造器并不是用于创建对象,而是让其子类调用这些构造器来完成属于抽象类的初始化操作。
  • 接口里不能包含初始化块;但抽象类则完全可以包含初始化块。
  • 一个类最多只能有一个直接父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java单继承的不足。

5.7 内部类

内部类住哟啊有如下作用。

  • 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类。
  • 内部类成员可以直接访问外部类的私有属性,因为内部类被当成其他外部类成员,同一个类的成员之间可以相互访问。但外部类不能访问内部类的实现细节,例如内部类的成员变量。
  • 匿名内部类适合用于创建那些仅需要一次使用的类。

从语法角度来看,定义内部类与定义外部类的语法大致相同,内部类除了需要定义在其他类里面之外,还存在如下两点区别。

  • 内部类比外部类可以多使用三个修饰符:private、protected、static——外部类不可以使用这三个修饰符。
  • 非静态内部类不能拥有静态成员。

5.7.1 非静态内部类

内部类定义语法格式如下。

public class OuterClass{//此处可以定义内部类
}

非静态内部类里不能有静态方法、静态成员变量、静态初始化块。

5.7.2 静态内部类

如果使用static来修饰一个内部类,则这个内部类就属于外部类本身,而不属于外部类的某个对象。因此使用static修饰的内部类被称为类内部类,有的地方也成为静态内部类。

public class StaticInnerClassTest{private int prop1 = 5;private static int pro2 = 9;static class StaticInnerClass{//静态内部类里可以包含静态成员private static int age;public void accessOuterProp(){//下面代码出现错误//静态内部类无法访问外部类的实例变量System.out.println(pro1);//下面代码正常System.out.println(pro2);}}
}

外部类依然不能直接访问静态内部类的成员,但可以使用静态内部类的类名作为调用者来访问静态内部类的类成员,也可以使用静态内部类对象作为调用者来访问静态内部类的实例成员。下面程序示范了这条规则。

public class AccessStaticInnerClass{static class StaticInnerClass{private static int prop1 = 5;private int prop2 = 9;}public void accessInnerProp(){//System.out.println(pro1);//上面代码出现错误,应改为如下形式//通过类名访问静态内部类的类成员System.out.println(StaticInnerClass.prop1);// System.out.println(prop2);// 上面代码出现错误,应该为如下形式// 通过实例访问静态内部类的实例变量System.out.println(new StaticInnerClass().prop2);}
}

5.7.3 使用内部类

  1. 在外部类内部使用内部类
  2. 在外部类以外使用非静态内部类
  • 省略访问控制符的内部类,只能被与外部类处于同一个包中的其他类所访问。
  • 使用protected修饰的内部类,可被与外部类处于同一个包中的其他类和外部类的子类所访问。
  • 使用public修饰的内部类,可以在任何地方被访问。
    在外部类以外的地方定义内部类(包括静态和非静态两种)变量的语法格式如下:
OuterClass.InnerClass varName

在外部类以外的地方创建非静态内部类实例的语法如下:

OuterInstance.new InnerConstructor()
class Out{//定义一个内部类,不适用访问控制符//即只有同一个包中的其他类可以访问该内部类class In{public In(String msg){System.out.println(msg);}}
}
public class CreateInnerInstance {public static void main(String[] args) {Out.In in = new Out().new In("测试信息");/*上面代码可改为如下三行代码使用OutterClass.InnerClass的形式定义内部类变量Out.In in创建外部类实例,非静态内部类实例将寄生在该实例中Out out = new Out();通过外部实例和new来调用内部类构造器创建非静态内部类实例in = out.new In("测试信息");*/}
}

上面程序粗体代码行创建了一个非静态内部类的对象。从上面代码可以看出,非静态内部类的构造器必须使用外部类对象来调用。
3.在外部类以外使用静态内部类
在外部类以外的地方创建静态内部类实例的语法如下:

new OuterClass.InnerConstructor()

下面程序示范了如何在外部类以外的地方创建静态内部类的实例。

class StaticOut{// 定义一个静态内部类,不适用访问控制符// 即同一个包中的其他类可以访问该类内部类static class StaticIn{public StaticIn(){System.out.println("静态内部类的构造器");}}
}
public class CreateStaticInnerInstance {public static void main(String[] args) {StaticOut.StaticIn in = new StaticOut.StaticIn();/*上面代码可改为如下两行代码使用OuterClass.InnerClass的形式定义内部类变量StaticOut.StaticIn in;通过new来调用内部类构造器创建静态内部类实例in = new StaticOut.StaticIn();*/}
}

5.7.4 局部内部类

如果把一个内部类放在方法里定义,则这个内部类就是一个局部内部类,局部内部类仅在该方法里有效。

public class LocalInnerClass {public static void main(String[] args) {//定义局部内部类class InnerBase{int a;}//定义局部内部类的子类class InnerSub extends InnerBase{int b;}//创建局部内部类的对象InnerSub is = new InnerSub();is.a = 5;is.b = 8;System.out.println("InnerSub对象的a和b实例变量是:"+ is.a + "," + is.b);}
}

5.7.5 Java 8 改进的匿名内部类

定义匿名内部类的格式如下:

new 实现接口() | 父类构造器(实参列表){//匿名内部类的类体部分
}

关于匿名内部类还有如下两条规则:

  • 匿名内部类不能是抽象类,因为系统在创建匿名内部类时,会立即创建匿名内部类的对象。因此不允许将匿名内部类定义成抽象类。
  • 匿名内部类不能定义构造器。
    最常用的创建匿名内部类的方式时许哟啊创建某个接口类型的对象,图下程序所示:
interface Product{public double getPrice();public String getName();
}
public class AnonymousTest {public void test(Product p){System.out.println("购买了一个" + p.getName() + ",花掉了" + p.getPrice());}public static void main(String[] args) {AnonymousTest ta = new AnonymousTest();//调用test()方法时,需要传入一个Product参数// 此处传入其匿名实现类的实例ta.test(new Product() {@Overridepublic double getPrice() {return 567.8;}@Overridepublic String getName() {return "AGP显卡";}});}
}

5.8 Java 8 新增的Lambda表达式

Lamdba表达式的主要作用就是代替匿名内部类的繁琐语句。它由三部分组成。

  • 形参列表。
  • 箭头(->)。
  • 代码块。
interface Eatable{void taste();
}
interface Flyable{void fly(String weather);
}
interface Addable{int add(int a, int b);
}
public class LambdaQs {//调用该方法需要Eatable对象public void eat(Eatable e){System.out.println(e);e.taste();}//调用该方法需要Flyable对象public void drive(Flyable f){System.out.println("我正在驾驶:" + f);f.fly("【碧空如洗的晴日】");}//调用该方法需要Addable对象public void test(Addable add){System.out.println("5和3的和为:" + add.add(5, 3));}public static void main(String[] args) {LambdaQs lq = new LambdaQs();//Lambda表达式的代码块只有一条语句,可以省略花括号lq.eat(()-> System.out.println("苹果味道不错!"));//Lambda表达式的形参列表只有一个形参,可以省略圆括号lq.drive(weather ->{System.out.println("今天天气是:" + weather);System.out.println("直升机飞行平稳");});// Lambda表达式的代码块只有一条语句,可以省略花括号// 代码块中只有一条语句,及时该表达式需要返回值,也可以省略return关键字lq.test(((a, b) -> a + b));}
}

5.8.2 Lambda表达式与函数式接口

Lambda表达式实现的是匿名方法——因此他只能实现特定函数式接口中的唯一方法。这意味着Lambda表达式有如下两个限制:

  • Lambda表达式的目标类型必须是明确的函数式接口。
  • Lambda表达式之只能为函数式接口创建对象。
    为保证Lambda表达式的目标类型是一个明确的函数式接口,可以有如下三种常见方式:
  • 将Lambda表达式赋值给函数式接口类型的变量。
  • 将Lambda表达式作为函数是接口类型的参数传给某个方法。
  • 使用函数式接口对Lambda表达式进行强制类型转换。
    Java 8 在java.util.function包下预定义了大量函数式接口,典型地包含如下4类接口:
  • XxxFunction:
  • XxxConsumer:
  • XxxxPredicate:
  • XxxSupplier:

5.8.3 方法引用和构造器引用

  1. 引用类方法
  2. 引用特定对象的实例方法
  3. 引用某类对象的实例方法
  4. 引用构造器

5.8.4 Lambda表达式与匿名内部类的联系和区别

Lambda表达式是匿名内部类的一种简化,因此它可以部分提取匿名内部类的作用,Lambda表达式与匿名内部类存在如下相同点:

  • Lambda表达式与匿名内部了一样,都可以直接访问“effectively final”的局部变量,以及外部类的成员变量(包括实例变量和类变量)。
  • Lambda表达式创建的对象与匿名内部类生成的对象一样,都可以直接调用从接口中继承的默认方法。
    Lambda表达式与匿名内部类主要存在如下区别:
  • 匿名内部类可以为任意接口创建实例——不管接口包含多少个抽象方法,只要匿名内部类实现所有的抽象方法即可;但Lambda表达式只能为函数式接口创建实例。
  • 匿名内部类可以为抽象类甚至普通类创建实例;但Lambda表达式只能为函数式接口创建实例。
  • 匿名内部类是实现的抽象方法的方法体允许调用接口中定义的默认方法;但Lambda表达式的代码块不允许调用接口的默认方法。

5.8.5 使用Lambda表达式调用Arrays的类方法

5.9 枚举类

在某些情况下,一个类的对象是有限而且固定的,比如季节类,它只有4个对象;再比如行星类,目前只有8个对象。这种实例有限而且固定的类,在Java里被称为枚举类。

5.9.1 手动实现枚举类

在早期代码中,可能会直接使用简单的静态常量来表示枚举,例如:

public static final int SEASON_SPRING = 1;
public static final int SEASON_SUMMER = 2;
public static final int SEASON_FALL = 3;
public static final int SEASON_WINTER = 4;

这种方法简单明了,但存在如下几个问题:

  • 类型不安全
  • 没有命名空间
  • 打印输出的意义不大

但枚举又确实有存在的意义,因此早期也可采用通过定义类的方式来实现,可以采用如下设计方式:

  • 通过private将构造器隐藏起来
  • 把这个类的所有可能实例都使用public static final修饰的类变量来保存
  • 如果有必要,可以提供一些静态方法,允许其他程序根据特定参数来获得与之匹配的实例
  • 使用枚举类可以使程序更加健壮,避免创建对象的随意性

5.9.2 枚举类入门

Java 5 新增了一个enum关键字(它与class、interface关键字的地位相同),用于定义枚举类。
但枚举类终究不是普通类,它与普通类有如下简单区别:

  • 枚举类可以实现一个或多个接口,使用enum定义的枚举类默认继承了java.lang.Enum类,而不是默认继承Object类,因此枚举类不能显式继承其他父类。
  • 使用enum定义、非抽象的枚举类默认会使用final修饰,因此枚举类不能派生子类。
  • 枚举类的构造器只能使用private访问控制符,如果省略了构造器的访问控制符,则默认使用private修饰;如果强调指定访问控制符,则只能指定private修饰符。
  • 枚举类的所有实例必须在枚举类的第一行显示列出,否则这个枚举类永远都不能产生实例。

java.lang.Enum类中提供了如下几个方法:

  • int compareTo(E o):
  • String name():
  • int ordinal():
  • String toString():
  • public static <T extends Enum>T valueOf(Class<T>enumType,String name);

5.9.3 枚举类的成员变量、方法和构造器

枚举类也是一种类,只是它是一种比较特殊的类,因此它一样可以定义成员变量,方法和构造器。

5.9.4 实现接口的枚举类

5.9.5 包含抽象方法的枚举类

5.10 修饰符的使用范围

本章练习

1.通过抽象类定义车类的模板,然后通过抽象的车类来派生拖拉机、卡车、小轿车。
2.定义一个接口,并使用匿名内部类方式创建接口的实例。
3.定义一个函数式接口,并使用Lambda表达式创建函数式接口的实例。
4.定义一个类,该类用于封装一桌梭哈游戏,这个类应该包含桌上剩下的牌的信息,并包含5个玩家的状态信息:他们各自的位置、游戏状态(正在游戏或已放弃)、手上已有的牌等信息。如果有可能,这个类还应该实现发牌方法,这个方法需要控制从谁开始发牌,不要发牌给放弃的人,并修改桌上剩下的牌。

疯狂Java讲义(读书笔记)(第五章)相关推荐

  1. 深入Java虚拟机读书笔记第五章Java虚拟机

    Java虚拟机 Java虚拟机之所以被称之为是虚拟的,就是因为它仅仅是由一个规范来定义的抽象计算机.因此,要运行某个Java程序,首先需要一个符合该规范的具体实现. Java虚拟机的生命周期 一个运行 ...

  2. 《疯狂的JAVA讲义》笔记-第8章集合

    <疯狂的JAVA讲义>笔记-第8章集合 Iterator .ListIterator接口 Iterator迭代时是将元素的值返回,并不是将元素本身返回,所以迭代时无法更改元素的值.但是可以 ...

  3. 《Python从入门到实践》读书笔记——第五章 if语句

    <Python从入门到实践>读书笔记--第五章 if语句 1. 一个简单示例 cars = ['audi', 'bwm', 'subaru', 'toyota']for car in ca ...

  4. java虚拟机读书笔记 第三章 垃圾收集器和内存分配策略

    java虚拟机读书笔记 第三章 垃圾收集器和内存分配策略 GC需要完成的三件事情:哪些内存需要回收.什么时候回收.如何回收 垃圾回收器在对堆进行回收前,首先要确定那些对象存活,哪些对象已经死去,判断的 ...

  5. 《深度探索C++对象模型》读书笔记第五章:构造析构拷贝语意学

    <深度探索C++对象模型>读书笔记第五章:构造析构拷贝语意学 对于abstract base class(抽象基类),class中的data member应该被初始化,并且只在constr ...

  6. 《Microsoft Sql server 2008 Internals》读书笔记--第五章Table(6)

      <Microsoft Sql server 2008 Internals>读书笔记订阅地址: http://www.cnblogs.com/downmoon/category/2303 ...

  7. 李刚 疯狂Python讲义 读书笔记

    疯狂Python讲义 李刚 这不一定是最好的python入门书,我买它纯粹是因为遇到公众号的推销.对入门教材不需要太纠结,基础知识部分大家都是互相借鉴的,买最近出版的就行. 我是经历了很长时间的碎片化 ...

  8. 《Microsoft Sql server 2008 Internals》读书笔记--第五章Table(4)

    <Microsoft Sql server 2008 Internals>索引目录: <Microsoft Sql server 2008 Internal>读书笔记--目录索 ...

  9. 《数据挖掘导论》Pangaea-Ning Tan 读书笔记 ----第五章 分类其他技术

    文章目录 第五章 分类:其他技术 5.1 基于规则的分类 5.1.1 基于规则的分类器的工作原理 5.1.2 规则的排序方案 5.2 最近邻算法(KNN) 无监督最近邻 KDTree和BallTree ...

  10. 《Core Java》读书笔记——第6章

    接口与内部类 本章代码 接口 接口不是类,而是对类的一组需求描述.以Comparable接口为例,对象所属的类如果实现了Comparable接口,Arrays类中的sort方法就可以对该类的对象数组进 ...

最新文章

  1. 腾讯 JDK 11 正式开源,高性能、太牛逼啦!
  2. java线程 同步与异步 线程池
  3. 脑机接口和卷积神经网络的初学者指南(二)
  4. Python语言学习:利用python语言实现调用内部命令(python调用Shell脚本)—命令提示符cmd的几种方法
  5. (~解题报告~)L1-016 查验身份证 (15分)(29行代码AC!)
  6. zplane函数怎么用m文件调用_matlab中一个m文件怎么调用另一个m文件的函数
  7. Awesomplete 屌爆了
  8. 未发现数据源名称并且未指定默认驱动程序_看我如何发现NVIDIA GeForce Experience代码执行漏洞...
  9. 浅谈n个球和m个盒子之间的乱伦关系
  10. Something about WMI
  11. docker image设置jdk版本_Docker 部署 Spring Boot
  12. 知识点收录01---关于Tomcat的一些知识点
  13. Linux下使用dd命令向U盘中写入ISO镜像
  14. 如何测试视频播放器?
  15. 内蒙古煤炭经济杂志社内蒙古煤炭经济编辑部2022年第14期目录
  16. Keil警告:warning: #223-D: function “xxx“ declared implicitly解决
  17. 日常运维工作的知识体系
  18. 《嵌入式 - 嵌入式大杂烩》详解J-Link RTT打印
  19. JS高频面试题,请查阅,务必收藏持续更新
  20. 微型计算机断电后信息将会丢失,2018年职称计算机考试题库(20)

热门文章

  1. VM虚拟机扩容centos8的硬盘
  2. 析达芬奇DM644x平台ARM中断处理流程
  3. java多线程实现龟兔赛跑
  4. 新浪nbsp;UTnbsp;将于nbsp;6月30日起停止服务
  5. 台式电脑 计算机管理在哪里,设备管理器在哪 怎么打开设备管理器?
  6. php 屏蔽搜索机器人,php实现判断访问来路是否为搜索引擎机器人的方法
  7. Explain执行计划key_len详解
  8. Kettle--java代码组件实现密码加密(BCryptPasswordEncoder)
  9. 任意两平面求夹角|Python练习系列[11]
  10. 笔记整理-MySQL高级