《西游记》第2集 官封弼马温

美猴王战胜了混世魔王,花果山上喜气洋洋,小猴们每日操演武艺,十分快乐。悟空闯入东海龙宫,向龙王索取镇海神针——如意金箍棒。这棒虽重一万三千五百斤,却大可撑天着地,小可变针,藏入耳内。悟空酒醉睡去,忽见两个阴差前来索命,悟空大闹阎罗殿,命判官取出生死簿,一笔勾去了猴类的生年死月。龙王、阎王上玉帝处告状,玉帝派太白金星下界招抚猴王,请他上天作官。悟空欣然前往,在武曲星君的捉弄下,玉帝封他做了弼马温。当悟空明白了自己不过是个马夫后,大怒之下回转花果山,扯起大旗,自称齐天大圣。玉帝不能容忍,叫托塔天王与哪吒率领天兵神将,杀向花果山。

1.类的属性定义

前面说过,对象有它自己的属性。属性是对象具有的各种特征,每个对象的每个属性都有特定值,是对于对象的基本信息或是当前状态等的描述。在Java中,属性可以是一个常量或者变量,一般的格式如下:

修饰符 属性类型 属性名=初始值;(初始值可以没有)

修饰符是指访问的权限限制,我们将在下节中讲解。

属性类型可以是一个简单类型,例如数字(孙悟空的年龄)、字符串(孙悟空的名字)等等,也可以是一个复杂类型,例如数组、集合等,还可以是另一个类,即一个对象可以是另一个对象的属性,也就是说对象可以是包含的关系。例如,金箍棒是孙悟空所有的一个物品,那么“金箍棒”类即可以定义为“孙悟空”类的一个属性。

这里希望你可以对属性有一个感性的认识,稍后我们会将每一种情况详细展开讲解。

把属性这里补充进去,“孙悟空”类可以写成:

那么如何在Java中精确定义出这个对象呢?我们首先需要了解Java中的数据类型定义及常量与变量的概念。

2 常量与变量

简单的说,变量就是在程序运行期间可以修改的量,常量就是在程序运行期间不能被修改的量。

孙悟空有两个名字,一个是他的本名,一个是他的别名。

孙悟空的本名就是孙悟空,提到“孙悟空”,你就能知道说的是谁,所以这是他的唯一固定标识,不允许被更改,这就是常量。

《西游记》第一回后半部分写他见到菩提祖师,祖师根据他是猴子(猢狲),为他取名为“孙”,法名“悟空”。他后来听从观音菩萨的劝告,拜唐僧为师参加取经,就正式启用“悟空”这一法号。

孙悟空的别名有很多,像孙行者就是他的别名。《西游记》中有提及,三藏欢喜道:“也正和我们的宗派。你这个模样,就象那小头陀一般,我再与你起个混名,称为行者,好么?”悟空道:“好!好!好!”自此时又称为孙行者。

在遇到唐三藏之前,他是没有别名的,在遇到他之后,便有了别名叫孙行者,这就是变量。当然,变量也是有访问权限限制的,不是谁都可以更改,后面会详细讲述。

除了这两个名字外,孙悟空还有一些外号,这是别人额外给他起的,像美猴王、孙大圣、泼猴等等。这个同样是可以改变的,是变量。除此之外,他的职务也是变量,最开始是“弼马温”,后来是“齐天大圣”。

2.1 常量

(1)常量表示的是在程序运行过程中不能被程序所修改的数据。

(2)声明常量必须用final关键字。

(3)常量分为:整型,浮点型,字符型,布尔型,字符串型常量。(注意,常量只能是一个值,不能是引用类型,即不能是类和对象)

语法:final <类型> variable=值;

因此,“孙悟空”类的姓名属性应该改为:

final字符串 姓名=“孙悟空”;

这样修改后的“孙悟空”类即为:

2.2 变量

为什么需要变量?

电脑使用内存来记忆计算时所使用的数据。数据各式各样,要先根据数据的需求(即类型)为它申请一块合适的空间,便有了十六位的内存在址。内存空间的数据有可能会被程序改变,而内存地址不方便记忆,因此产生了变量——即,通过内存中小空间的别名找到数据存储的位置。

内存地址不好记,怎么办?

通过内存中小空间的别名找到数据存储的位置。

一个变量是存储数据的一个基本单元。

变量的应用即为:

1、在内存中存储弼马温这个职位的数据

2、显示内存中存储的数据的值

在“孙悟空”类的属性中,除了绝对不可改变的姓名外,其他的均是变量。使用一个变量的步骤如下:

变量的声明和赋值可以是以下两种:

1.在声明的同时赋值,格式为:数据类型 变量名 = 数值;

例如“孙悟空”类中的年龄属性: 数字 年龄=1226;

2.先声明,后赋值

格式为:数据类型 变量名;

变量名 = 数值;

例如“孙悟空”类中的年龄属性:

数字 年龄;

年龄=1226;

在Java语言中,变量命名要符合一定规则,由字母、数字、下划线或美元符号($)组成,但只能由字母、下划线或美元符号($)开头,但我建议尽量避免使用$符号。一般是以变量所表达的意义的英文单词组成,如果多于一个单词的,第一个单词首字母小写,其他单词的首字母大写,如下:

变量分为局部变量和成员变量。

局部变量是在方法内定义的变量,只是相应的方法体内或程序块内有效;成员变量是在类中定义的,即是属性(又称全局变量)可以通过对象引用。是哪种变量,主要是看它的定义位置,如果是在类中定义的,那么就在整个类中有效,如果是在类的方法中定义的,就只在方法中有效。这里大家先记下这个作用域的概念,之后讲到方法时会更直观的了解。

局部变量在使用之前,必须先初始化,否则不能直接使用。

成员变量(属性/全局变量)如果没有初始化,在使用时,系统将会自动赋一个默认的初始值,如下表:

由上表即可以看到,Java中的数据类型分为基本类型和引用类型,基本类型中除了布尔型的值初始为false外,其他类型的初始值都是0,而引用类型的初始值为null。

null是Java的关键字,它的意思就是“空”,代表什么都没有,后面会再次介绍。在一开始的时候,孙悟空这个对象,“手上拿的东西”这一属性就是空的(null),直到他闯入东海龙宫,向龙王索取了镇海神针,这一属性才有了值:如意金箍棒。

下面我们来讲一下Java中的基本类型和引用类型。

3 Java数据类型-基本类型

在Java中代码中,每个变量都必须声明一种类型(type)。数据类型分为基本类型(primitive types)和引用类型(reference types)。

3.1 什么是基本类型

Java为基本类型提供语言级别的支持,即已经在Java中预定义,用相应的保留关键字表示。基本类型是单个值,而不是复杂的对象,基本类型不是面向对象的,主要出去效率方面的考虑,但是同时也提供基本类型的对象版本,即基本类型的包装器(wrapper)。可以直接使用这些基本类型,也可以使用基本类型构造数组或者其他自定义类型。基本类型具有明确的取值范围和数学行为。

即是八个原始数据类型,大体可分为四种:

l 逻辑类 Boolean 布尔型,像孙悟空的脸上是否有毛这个属性,即属于布尔型,布尔型的数据选值只能是true(是)和false(否)。

例如:boolean hasHair = true;//将变量truth赋值为真,即的确有毛

l 文本类 char 字符型,注意,这里指的可不是字符串(字符串类型是String,它是对象,不属于基本类型,而是引用类型,下面会讲到),而是单个字符,例如:孙悟空的性别标识,那就应该定义为字符型,取值可以是“男(M)”或者“女(F)” 。字符型的数据以单引号(‘’)包含。

例如:char sex = ‘M’;//孙悟空应该为男性

l 整数类 byte, short, int, long,这四种类型均用来保存整数类的数据,区别只是存储的数据大小不同,像孙悟空的年龄,定义为short类型即可,具体的数值范围可以参照下表。

l 浮点类 float,double,这两种类型均用来保存浮点型的数据(即带小点数的数字),区别只是存储的数据大小不同,像孙悟空的体重,可能就不是整数,可以定义为float类型,具体的数值范围可以参照下面的基本数据类型对比表:

所有的教程都会列出这些数值范围,但是我相信没有人能记得住,这里并不需要你背下来,只需要了解一下即可,需要的时候可以速查。

我一直强调,学习编程,并不需要死记硬背,主要是要了解思想(即:知道写这段代码的思路),以及对java知识的感性认识(即:知道它有什么,都是做什么用的),在实际应用中,完全可以速查。

毕竟,这不是闭卷考试。

由上面的介绍我们可以判断出,“孙悟空”类中,以下属性是基本类型的,包括年龄、脸上是否有毛、屁股上是否有尾巴:

整理一下,Java的数据类型分为三大类,即布尔型、字符型和数值型,而其中数值型又分为整型和浮点型,Java的变量类型为布尔型boolean;字符型char;整型byte、short、int、long;浮点型float、double。

在Java中,整型、实型、字符型等这些基本数据类型。按存储空间(即能存储数值的大小)由低级到高级分别为:

(byte,short,char )->int->long->float->double。

3.2类型转换

四种整型变量和两种浮点型变量分别对应于不同的精度和范围。此外,我们还经常用到一种类变量,即String。下面的论述中,我们将阐述如何实现这些转换。

数据类型之间的转换方式有如下三种:

l 低级到高级的自动类型转换

l 高级到低级的强制类型转换

l 包装类过渡类型转换

下面我们来分别讲解:

自动类型转换

低级变量可以直接转换为高级变量,称之为自动类型转换。自动转换时发生扩宽(widening conversion)。因为较大的类型(如int)要保存较小的类型(如byte),内存总是足够的,不需要强制转换。如果将字面值保存到byte、short、char、long的时候,也会自动进行类型转换。注意区别,此时从int(没有带L的整型字面值为int)到byte/short/char也是自动完成的,虽然它们都比int小。在自动类型转化中,除了以下几种情况可能会导致精度损失以外,其他的转换都不能出现精度损失。

int型数据--> float

long型数据--> float

long型数据--> double

float型数据 -->double without strictfp

除了可能的精度损失外,自动转换不会出现任何运行时(run-time)异常,异常会在后面章节讲解,这里可以理解为不会发生错误。

例如:

byte b;

int i=b;

long l=b;

float f=b;

double d=b;

完全可以直接去赋值,默认即可完成转换,不会出错。

强制类型转换

如果将高级变量转换为低级变量时,或者在同级的short与char之间进行转换,就必须强制转换,也被称作缩小转换(narrowing conversion),因为必须显式地使数值更小以适应目标类型。强制转换采用转换操作符()。严格地说,将byte转为char不属于narrowing conversion),因为从byte到char的过程其实是byte-->int-->char,所以widening和narrowing都有。强制转换除了可能的精度损失外,还可能使模(overall magnitude)发生变化。强制转换格式如下:

(target-type) value

例如:

// 定义short 整型变量 i 并且赋值

short i=99;

// 将 i 强制类型转换为 char 型变量

char c=(char)i;

如果整数的值超出了byte所能表示的范围,结果将对byte类型的范围取余数。例如a=256超出了byte的[-128,127]的范围,所以将257除以byte的范围(256)取余数得到b=1;需要注意的是,当a=200时,此时除了256取余数应该为-56,而不是200.

将浮点类型赋给整数类型的时候,会发生截尾(truncation)。也就是把小数的部分去掉,只留下整数部分。此时如果整数超出目标类型范围,一样将对目标类型的范围取余数。

基本类型转换总结如下图:

注:蓝色的部分为正常转换,黄色的部分为会发生截尾。

包装类过渡类型转换

什么是包装类?

包装类,就是可以直接将简单类型的变量表示为一个类

在执行变量类型的相互转换时,我们会大量使用这些包装类

Java共有六个包装类,分别是Boolean、Character、Integer、Long、Float和Double,分别对应于 boolean、char、int、long、float和double

String本身就是类。所以也就不存在什么包装类的概念了

在进行简单数据类型之间的转换(自动转换或强制转换)时,可以利用包装类进行中间过渡。

一般情况下,首先声明一个变量,然后生成一个对应的包装类,就可以利用包装类的各种方法进行类型转换了。

简单类型的变量转换为相应的包装类,可以利用包装类的构造函数。即:

Ø Boolean(boolean value)orBoolean(String value)

Ø Character(char value)orCharacter(String value)

Ø Integer(int value)orInteger(String value)

Ø Long(long value)orLong(String value)

Ø Float(float value)orFloat(String value)

Ø Double(double value)orDouble(String value)

而在各个包装类中,有xxxValue()的方法,来得到其对应的简单类型数据。利用这种方法,也可以实现不同数值型变量间的转换。

例如,对于一个双精度实型类,intValue()可以得到其对应的整型变量,而doubleValue()可以得到其对应的双精度实型变量。

所有类中均提供了toString()方法,即将该类转换为字符串。例如:Characrer,Integer,Float,Double,Boolean,Short等类的toString()方法用于将字符、整数、浮点数、双精度数、逻辑数、短整型等类转换为字符串。

在实际程序应用中,最常用的就是各个基本类型与字符串(String)间的转换。一般由字符串转换成基本类型,使用各个包装类中的xxxValue()或者parseXXX()方法,例如:

String a = "55";

//将上面的字符串转换成整型

int i1 = new Integer(a).intValue();//使用包装类所生成对象的xxxValue()方法

int i2 = Integer.parseInt(a);//使用包装类的parseXXX()方法

而在将基本类型转换成字符串时,多使用包装类toString()方法以及String类的valueOf()方法。例如:

int i= 55;

//将上面的整型数据转换成字符串

String a1 = new Integer(i).toString();//包装类所生成对象的toString()方法

String a2 = String.valueOf(i);//使用String类的valueOf()方法

需要生成对象再调用的叫做实例方法,而通过类名直接调用的称为类方法。上面我们学到过,通过new关键字可以生成对象,因此可以看得出,上面的xxxValue()和toString()方法就是实例方法,而parseXXX()和valueOf()是通过类名直接调用的,属于类方法,关于实例方法与类方法,请先有个基本的使用区分,我们在下面章节再详细讲解。

很多人都会觉得字符串也应该是基本类型的,因为这个是最常用的,但是在Java中,没有内置这个类型,字符串常量是作为String类的对象存在的,因此它属于引用类型,下面我们便来讲解引用类型。

4 Java数据类型-引用类型

4.1 什么是引用类型

引用类型就是指类型不是基本类型,而是一个类类型的数据,比如“孙悟空”类中的字符串类型以及“金箍棒”类类型。你也可以这样理解,除了上面讲到的基本类型之外,任何其他的类型定义均为引用类型。

4.2 字符串

字符串指的是字符的序列。前面说过,在Java中,没有内置的字符串类型,字符串常量是作为String类的对象存在的。因此,每个属性均相当于创建了一个String类对象。

之前我们接触过,每个类都有一个或多个构造函数,String类也不例外,在创建String类对象时,通常需要向构造函数传递参数来指定创建的字符串的内容,常用的String类构造函数:

public String():该构造函数用于创建一个空的字符串常量。

public String(String value):该构造函数用于根据一个已经存在的字符串常量来创建一个新的字符串常量,该字符串的内容和已经存在的字符串常量一致。

String(byte[] bytes, String charsetName) :该构造函数构造一个新的 String,使用指定的字符集解码指定的字节数组。

public String(char value[]):该构造函数用于根据一个已经存在的字符数组来创建一个新的字符串常量。(数组将在本章后面的内容中介绍)

public String(StringBuffer buffer):该构造函数用于根据一个已经存在的StringBuffer对象来创建一个新的字符串常量。StringBuffer是变长的字符串,将在下面讲解。

由于字符串是最常用的一种类型,因此Java中增加了便捷的定义方式:

String 变量名 = “值”; 即相当于:String 变量名 = new String(“值”);

前面我们讲过,既然是类,那么就会有相应的操作方法,String类对象的常用操作及方法如下:

Ø int indexOf(String str):返回第一次出现的指定子字符串在此字符串中的索引

例如,想查寻“孙悟空”这个字符串中,姓所在的位置,那么就可以用此方法:

String str = "孙悟空";

int index = str.indexOf("孙");

得到的结果就是0。Java语言中,所有标号是从0开始的,因此第一个位置的标号为0。包括数组、循环等都是从0开始的。

Ø int indexOf(String str, int fromIndex):从指定的索引处开始,返回第一次出现的指定子字符串在此字符串中的索引。如果被查询的字符串仅出现一次,那么这个方法与上面的方法返回的结果是相同的,但是如果出现了不止一次,那么将会有不同的返回结果。

例如,想查寻“孙悟空打败了假孙悟空”这个字符串中,“空”所在的位置,那么就可以看出差别:

String str = "孙悟空打败了假孙悟空";

int index1 = str.indexOf("空");//结果为2

int index2 = str.indexOf("空", 4); //结果为9

这种方法名相同,但是参数不同的方法,叫做方法的重载,将在下面讲到Java的多态时详细讲解。

Ø int lastIndexOf(String str):返回最后一次出现的指定字符串在此字符串中的索引。

例如,想查寻“孙悟空打败了假孙悟空”这个字符串中,“空”最后一次的位置:

String str = "孙悟空打败了假孙悟空";

int index1 = str.lastIndexOf("空");//结果为9

Ø int lastIndexOf(String str, int fromIndex):从指定的索引处开始进行反向搜索,就是相当于限定了搜索的范围是在0与fromIndex之间,结果仍然是返回最后一次出现的指定字符串在此字符串中的索引。使用及结果情况与indexOf相似。

例如,同样是想查寻“孙悟空打败了假孙悟空”这个字符串中,“空”最后一次的位置:

String str = "孙悟空打败了假孙悟空";

int index1 = str.lastIndexOf("空");//结果为9

int index2 = str.lastIndexOf("空", 4);//结果为2,限定了搜索的范围是在0与4之间

总结:以上4个方法都是查找位置,如果没有找到相应的字符串,均是返回-1,一个很常用的用法为:将是否存在做为判断的条件,例如:

String str = "孙悟空";

//如果"孙悟空"这个字符串中含有"孙"这个字符串的话

//if是判断语句,将在下面进行讲解

if(str.indexOf("孙") != -1){

//TODO:执行代码

}

Ø int length():返回此字符串的长度

例如:

String str = "孙悟空";

System.out.println(str.length());//结果为3

由此可见,每个字符串的可用位置标号都是从0到(字符串.length()-1)。

Ø String replaceFirst(String regex, String replacement):该方法用字符串replacement的内容替换当前字符串中遇到的第一个和字符串regex相一致的子串,并将产生的新字符串返回。

例如:

String str = "孙悟空打败了假孙悟空";

System.out.println(str.replaceFirst("孙悟空","孙行者"));

//结果为:孙行者打败了假孙悟空

Ø String replaceAll(String regex, String replacement) :该方法用字符串replacement的内容替换当前字符串中遇到的所有和字符串regex相一致的子串,并将产生的新字符串返回

例如:

String str = "孙悟空打败了假孙悟空";

System.out.println(str.replaceAll("孙悟空","孙行者"));

//结果为:孙行者打败了假孙行者

Ø String[] split(String regex):根据给定的字符串来拆分此字符串,得到一个字符串数组, String[]是元素为字符串的数组,我们将在下面讲解

例如上例中的那个字符串:

String str = "孙悟空打败了假孙悟空";

String[] childs = str.split("打败了");

通过split方法,我们将得到一个长度为2的字符串数组,里面有2个Spring元素,分别为"孙悟空"和"假孙悟空"。

这个只是举例说明,在真实的程序编写中,最多的用法是将关联的数据以一定的特殊符号间隔开,便于整体存储,比如,西游团队的四个人,就可以存储在一起,用逗号分隔:

String str = "唐僧,孙悟空,猪八戒,沙僧";

String[] childs = str.split(",");

这样得到的childs这个数组中就会有4个Spring元素,分别为"唐僧"、"孙悟空"、"猪八戒"和"沙僧"。

Ø boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始,常用于条件判断

例如:

String str = "孙悟空";

if(str.startsWith("孙")){

//TODO:如果str这个字符串是以"孙"开头的,那么执行以下代码

}else{

//TODO:如果str这个字符串不是以"孙"开头的,那么执行以下代码

}

String str = "孙悟空";

if(str.startsWith("孙")){

//TODO:如果str这个字符串是以"孙"开头的,那么执行以下代码

}else{

//TODO:如果str这个字符串不是以"孙"开头的,那么执行以下代码

}

Ø String substring(int beginIndex):返回一个新的字符串,它是此字符串的一个子字符串

Ø String substring(int beginIndex, int endIndex):返回一个新字符串,它是此字符串的一个子字符串

以上两个方法同样是String中的两个重载的方法,如果指定了beginIndex和endIndex,那么就返回这两个位置标号中间的字符串,如果只指定了beginIndex,那么就返回从beginIndex这个位置标号到整个字符串结尾的字符串。

例如:

String str = "孙悟空打败了假孙悟空";

System.out.println(str.substring (3));//结果为:"打败了假孙悟空"

System.out.println(str.substring (3, 5));//结果为:"打败"

Ø String toLowerCase():把字符串转换为小写

Ø String toUpperCase():把字符串转换为大写

以上两个方法主要针对于英文组成的字符串。

例如:

String str = "WoShiSunWukong";

System.out.println(str.toLowerCase());//结果为:"woshisunwukong"

System.out.println(str.toUpperCase());//结果为:"WOSHISUNWUKONG"

Ø String trim():去掉字符串两端的空格。此方法可以去掉该字符串首尾的空格、制表符等,一般用于验证用户名、密码输入框。

例如:

String str = " 孙悟 空 ";

System.out.println(str.trim());//结果为:"孙悟 空"

此方法只会去除两端的空格,不会去除中间夹着的空格。如果想去除包含中间的全部空格,那么就要用之前讲过的replaceAll方法:

String str = " 孙悟 空 ";

System.out.println(str.replaceAll(" ", ""));//结果为:"孙悟空"

Ø static String valueOf(XXX b):把其他类型变量转成字符串

任意类型的数据都可以通过这个方法转成字符串,其他类型的好理解,那么布尔型数据会转成什么呢?答案是"true"或者"false"。

例如:

boolean b = false;

System.out.println(String.valueOf(b));//结果为:"false"

上面的方法会在我们编程中大量使用,因此,务必要熟练掌握和使用。

4.3 空字符串与NULL

上面讲过,所有的引用类型,如果不指定初始值的话,默认都是null。Java中,null是一个关键字,用来标识一个不确定的对象,或者说是一个不存在的对象。可以将null赋给引用类型变量,但不可以将null赋给基本类型变量。

null本身虽然能代表一个不确定的对象,但就null本身来说,它不是对象,也不知道什么类型,也不是java.lang.Object的实例(所有的对象都是java.lang.Object的子类,在下面讲到继承的时候会讲解)。如果一个引用类型不被初始化,那么它就是没有分配内存没有内存地址,是不存在且不可用的,用null只是来标识这种情况。另外,null还有一个作用就是通知JVM释放内存,让一个非null的引用类型变量指向null,这样这个对象就不再被任何对象应用了,等待JVM垃圾回收机制去回收。

如果一个String类型的数据没有初始化,那么它的值也是null,是不是就是等于""呢?

答案是否定的。null代表声明了一个空对象,根本就不是一个字符串。而""代表声明了一个对象实例,这个对象实例的值是一个长度为0的空字符串。null代表声明了一个空对象,对空对象做任何操作都不行的,除了=和==,而且也不能调用String类的方法,而""则是一个字符串,只是这个字符串里面没有内容,但是任何字符串的操作都是可以用的,而且可以调用String类的全部方法。

可以这样理解:

String s=""; 是你没说任何话

String s = null; 是你根本就没法说话

或者说,""是空气,而null则是真空。

4.4 变长的字符串--StringBuffer类

与String类不同,StringBuffer类是一个在操作中可以更改其内容的字符串类。一旦创建StringBuffer类的对象,在操作中可以更改和变动字符串的内容。也就是说对于StringBuffer类的对象不仅能进行查找和比较等操作,也可以做添加、插入、修改之类的操作。

StringBuffer相当于是我们一开始不确定我们的字符串是什么样子的,有多少字符,因此我们先定义一块区域,然后再往里插入和添加,最后插入完了,再统一生成出一个字符串,最常用的添加方法就是append()。

大家看一下这两段代码:

String s1 = "我是" + "孙悟空" + ",今年" + String.valusOf(1226) + "岁";

String s2 = new StringBuffer().append("我是").append("孙悟空").append(",今年").append(1226).append("岁").toString();

这两句代码执行完成后的效果是一样的,那么除了写法上简单整齐一些之外,还有什么不同呢?

String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且大量浪费有限的内存空间。而StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。 每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量。

StringBuffer类提供了多种构造方法来创建类StringBuffer的对象:

public StringBuffer():创建一个空字符串缓冲区,默认初始长度为16个字符。

public StringBuffer(int length):length指定的初始长度创建一个空字符串缓冲区

public StringBuffer(String str):用指定的字符串str创建一个字符串缓冲区,其长度为str的长度再加16个字符。

10个重载的append方法,参数分别是不同的数据类型,可以在字符串缓冲区末尾追加boolean、char、字符数组、double、float、int、long、string、Object等类型的新内容,append方法的返回类型均为StringBuffer。

9个重载的insert方法,参数分别是不同的数据类型,可以在字符串缓冲区中指定位置处插入char 、字符数组、double、float、int、long、boolean、string、Object等类型的新内容。insert方法的返回类型均为StringBuffer。

在稍后的例子学习中,会逐步的用到这些类与方法,争取越来越熟练。

4.5大数据处理(超大的整数和浮点数)

Java里面整型int与浮点型float,double它们存放数据的范围是有边界的。那么如果需要更大的数据时,这些数据类型肯定是满足不了这种需求,所以就用到了BigInteger(超大的整数)和BigDecimal(超大的浮点数)这两个类来解决这个问题。这两个都不是基本类型,而是类,因此同样属于引用类型。

例如,我们想定义孙悟空身上有多少根毛,这个绝对是超过了long型的最大范围了,那么我们就可以定义为BigInteger :

BigIntegerallHair; //未设置初始值,因为我也不知道多少根

这两个类的对象能表示最大范围不清楚,理论上能够表示无限大的数,只要计算机内存足够大。这两个类都在java.math.*包中,因此想使用的话,必须在类开头处引用该包。这里暂时可以先记住,将在“引入工具包”章节中进行详细讲解,引入了之后,就可以像String一样来调用方法来使用了。

由于它不属于基本类型,因此运算不能使用“+”、“-”、“*”、“/”等运算符号,而是用方法来完成。下面我们通过两个例子来说明如何使用这两个类:

BigInteger:

//引入工具包,在后面讲解

import java.math.*;

public class BigIntegerTest {

public static void main(String[] args) {

//BigInteger类型的常量

BigInteger A = BigInteger.ONE;

System.out.println("BigInteger.ONE的结果为 " + A);//1

BigInteger B = BigInteger.TEN;

System.out.println("BigInteger.TEN的结果为 " + B);//10

BigInteger C = BigInteger.ZERO;

System.out.println("BigInteger.ZERO的结果为 " + C);//0

//初始化

BigInteger c = new BigInteger("12345670",8);//c = 12345670 八进制

System.out.println(c);//2739128

BigInteger d = BigInteger.valueOf(100);//d = 100

BigInteger e = new BigInteger(newbyte[]{1,0});//00000001 00000000

System.out.println(e);//256

System.out.println(e.bitCount());

System.out.println(e.bitLength());

//运算

BigInteger a = BigInteger.valueOf(1005550);

BigInteger b = BigInteger.valueOf(1044000);

BigInteger c1 = a.add(b); // 大数加法

System.out.println("加的结果为 " + c1);

BigInteger c2 = a.subtract(b); // 大数减法

System.out.println("减的结果为 " + c2);

BigInteger c3 = a.multiply(b); // 大数乘法

System.out.println("乘的结果为 " + c3);

BigInteger c4 = a.divide(b); // 大数除法

System.out.println("除的结果为 " + c4);

BigInteger c5 = a.mod(b);

System.out.println("模的结果为 " + c5);

BigInteger cc5 = a.remainder(b);

System.out.println("余的结果为 " + cc5);

BigInteger c6 = a.max(b);// 取最大

System.out.println("最大为 " + c6);

BigInteger c7 = a.min(b); // 取最小

System.out.println("最小为 " + c7);

BigInteger c8 = a.pow(10); //指数运算

System.out.println("指数运算结果为" + c8);

if (a.equals(b)) // 判断是否相等

System.out.println("相等");

else

System.out.println("不相等");

BigInteger c10 = a.abs(); // 求绝对值

System.out.println("a的绝对值为 " + c10);

BigInteger c11 = a.negate(); // 求相反数

System.out.println("a的相反数为 " + c11);

}

}

输出结果为:

BigInteger.ONE的结果为 1

BigInteger.TEN的结果为 10

BigInteger.ZERO的结果为 0

2739128

256

1

9

加的结果为 2049550

减的结果为 -38450

乘的结果为 1049794200000

除的结果为 0

模的结果为 1005550

余的结果为 1005550

最大为 1044000

最小为 1005550

指数运算结果为1056906827544881411951404077372867677711484472656250000000000

不相等

a的绝对值为 1005550

a的相反数为 -1005550

BigDecimal:

//引入工具包,在后面讲解

import java.math.*;

public class BigDecimalTest {

public static void main(String[] args) {

//BigDecimal类型的常量

BigDecimal A = BigDecimal.ONE;

System.out.println("BigDecimal.ONE的结果为 " + A);//1

BigDecimal B = BigDecimal.TEN;

System.out.println("BigDecimal.TEN的结果为 " + B);//10

BigDecimal C = BigDecimal.ZERO;

System.out.println("BigDecimal.ZERO的结果为 " + C);//0

//初始化

BigDecimal a = new BigDecimal("89.12345678987654321");

BigDecimal b = new BigDecimal("1000");

BigDecimal e = new BigDecimal(newchar[]{'2','1','.','2'});

System.out.println(e);//21.2

//运算

BigDecimal a = new BigDecimal("89.1234");

BigDecimal b = new BigDecimal("1000.36728834");

BigDecimal c1 = a.add(b); // 大数加法

System.out.println("加的结果为 " + c1);

BigDecimal c2 = a.subtract(b); // 大数减法

System.out.println("减的结果为 " + c2);

BigDecimal c3 = a.multiply(b); // 大数乘法

System.out.println("乘的结果为 " + c3);

//注意,这里如果不能除尽,就会抛出一个ArithmeticException错误

BigDecimal c4 = a.divide(b); // 大数除法

System.out.println("除的结果为 " + c4);

BigDecimal cc5 = a.remainder(b);

System.out.println("余的结果为 " + cc5);

BigDecimal c6 = a.max(b);// 取最大

System.out.println("最大为 " + c6);

BigDecimal c7 = a.min(b); // 取最小

System.out.println("最小为 " + c7);

BigDecimal c8 = a.pow(10); //指数运算

System.out.println("指数运算结果为" + c8);

if (a.equals(b)) // 判断是否相等

System.out.println("相等");

else

System.out.println("不相等");

BigDecimal c10 = a.abs(); // 求绝对值

System.out.println("a的绝对值为 " + c10);

BigDecimal c11 = a.negate(); // 求相反数

System.out.println("a的相反数为 " + c11);

}

}

输出结果为:

BigDecimal.ONE的结果为 1

BigDecimal.TEN的结果为 10

BigDecimal.ZERO的结果为 0

21.2

加的结果为 1089.12345678987654321

减的结果为 -910.87654321012345679

乘的结果为 89123.45678987654321000

除的结果为 0.08912345678987654321

余的结果为 89.12345678987654321

最大为 1000

最小为 89.12345678987654321

指数运算结果为31616968703194087333.71474887174406077078834132429726194300860779253381797884337048064650178740361301799617209955812260340316817120048633156996017759816867243104420462962178656466746940511201

不相等

a的绝对值为 89.12345678987654321

a的相反数为 -89.12345678987654321

说明一下:

//创建BigDecimal对象

BigDecimal bigNumber = new BigDecimal("89.1234567890123456789");

BigDecimal bigRate = new BigDecimal(1000);

BigDecimal bigResult = new BigDecimal(); //对象bigResult的值为0.0

注意,BigDecimal中的divide函数和BigInteger中的稍有不同。

方法1:

pubilc BigDecimal divide(BigDecimal divisor)

API中的解释: 返回一个 BigDecimal,其值为 (this / divisor),其首选标度为 (this.scale() - divisor.scale());如果无法表示准确的商值(因为它有无穷的十进制扩展),则抛出 ArithmeticException。

方法2:

pubilc BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)

scale指的是小数点后的位数。比如123.456则scale就是3,是BigDecimal类中的方法啊。

比如:BigDecimal b = new BigDecimal("123.456");//b.scale(),返回的就是3.

roundingMode是小数的保留模式。它们都是BigDecimal中的常量字段。

比如:BigDecimal.ROUND_HALF_UP表示的就是4舍5入。

pubilc BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)

它的意思是说:我用一个BigDecimal对象除以divisor后的结果,并且要求这个结果保留有scale个小数位,roundingMode表示的就是保留模式,是四舍五入啊还是其它的,你可以自己选!

通过上面两个例子,我们应该了解了对于超大数据的运算处理方式,像很多银行或者证券类的功能中,我们会大量用到这两个类。对于不熟悉的类,大家应该养成查看API的好习惯,上面会包含可用的常量、属性及方法。

4.6其他类的对象做属性

前面说地,对象可以通过“.”运算符来调用自己的属性和方法。因此,如果类中的一个属性是另一个类的对象,那么就要以通过这个对象,来调用另一个类中的方法,这个原理其实与String是相同的。

例如:“孙悟空”类中的一个属性是:金箍棒类 手上拿的东西;

那么,就可以通过这个对象,来调用“金箍棒”类中的方法:手上拿的东西.击打();

这个也是Java属性的一个精髓所在,通过这样就可以将各个对象关联起来,形容更复杂的关系,也就可以实现更复杂的功能。

把上面讲到的类型定义,以及类与变量起名规则,放到“孙悟空”类的定义中使其丰富一下,就可以这样写:

4.7 数组

什么是数组?

数组就是一个长度固定的数据结构,它存储多个相同类型的元素(或数值)。比如,西游团队就是一个数组,里面的元素都是人;孙悟空从蟠桃会上拿回来的装桃子的麻袋也是一个数组,里面的元素都是桃子。

前面我们讲过,一切皆对象,因此,数组也是一个对象。

数组的下标都是从0开始的,这一点和我们自然的认识些不同。为什么不是从1开始呢?是因为数组下标实际上是偏移量。数组元素位置的计算是以首个元素(地址)为基准,以偏移个数乘以元素所占空间大小来计算,这个偏移量就是数组个下标数,首个元素相对于自己是偏移了0个,所以数组的下标起始从0开始。

在Java中,数组可以是任何类型的──原始类型或类类型,也就是说,数组元素可以是原始类型的量,也可以是某一个类的对象。比如,“孙悟空”类中,可以有一个属性,叫做:出生地坐标,这个是一个元素为基本类型(数字)的数组;还可以有一个属性,叫做:所管理的猴子猴孙,这个属性的类型就是一个元素为“猴”类的数组。

根据数组类型,一般分为简单类型数组(数组的元素为8种基本类型)和复杂类型数组(数组元素为其它类)

简单类型数组在用new运算符建立时既分配了内存空间又赋上了初始默认值

复杂类型数组建立之后每个元素都是空值

数组的创建一般需要以下三个步骤:

l 数组的声明

数组元素类型 数组名[ ];

例: float 出生地坐标[];

猴 所管理的猴子猴孙[];

l 创建数组空间

创建是给数组分配内存空间,它可以直接使用new运算符,也可以直接用枚举来创建。格式如下:

数组名 = new 数组元素类型[数组长度];

例如:

出生地坐标= new float[2]; //经度、纬度

所管理的猴子猴孙= new 猴[20000];

创建数组空间的工作可以和声明数组的工作组合在一起用一条语句来实现。

float出生地坐标[]; 出生地坐标= new float[2];

等价于:

float出生地坐标[]= new float[2];

或者使用枚举创建数组:

float出生地坐标[] = { 126, -63 };

l 初始化数组

数组中的各元素是有先后次序的,每个数组元素用数组的名字和它在数组中的位置来表达。

在上一节创建的数组“所管理的猴子猴孙”中,所管理的猴子猴孙[0]表示数组“所管理的猴子猴孙”中的第一个元素,所管理的猴子猴孙[1]表示数组“所管理的猴子猴孙”中的第二个元素,依次类推,数组中的最后一个元素为所管理的猴子猴孙[19999]

初始化数组就是要使数组中的各个元素有确定的数值,如用枚举法定义的数组就不需要初始化了。而用new运算符定义的数组则需要根据实际情况赋值。

如果数组元素的类型是基本数据类型,由于基本数据类型都有缺省值,数组元素都自动初始化为缺省值。

对于以某个类的对象为数组元素的数组,初始化每个数组元素是必须的。

所有的数组都有一个属性length,这个属性存储了数组元素的个数。注意检查数组下标是否越界

数组都可以用循环的方式来赋值以及遍历取值,这个方式将在讲到循环结构的时候再进行讲解。

命令行参数

记得这个老熟人吧,从我们一开始的时候就接触过它,这个就是一个数组。我们来重温一下,温故而知新。

每个Java应用程序都有一个带String[] arg参数的main方法,该方法将可以接收一个字符串数组作为命令行参数:

public static void main(String[] args)

args[0] ->第一个参数(程序名不存储在args数组中)

args[1] ->第二个参数

args.length ->参数个数

例如:执行“java Message –xitian 唐僧 SunWukong”,则

args[0]:“-xitian”

args[1]:“唐僧”

args[2]:“SunWukong”

数组类的使用

在“java.util”包中,提供一个数组类Arrays,该类提供了一些方法用于排序、查找等操作,在编写程序中可以直接使用这些方法。这个工具的使用与之前的大数据据类型一样,也需要引入相应的工具包:

import java.util.Arrays;

4.7.1 转换成字符串

为什么之前说字符串是程序中最主要的部分,就是因为字符串是在生活中最常用理解与使用的一个格式。虽然为了程序编写方便而构造出了很多其他的数据类型,但是在很多情况下我们仍然是需要将其转换成字符串格式。很多数据格式也都提供了与字符串之间方便的转换方法,数组也不例外。

对于简单类型的一维数组,可以使用如下方法:

public static String toString(Xxx[] a)

返回包含a中数据元素的字符串,这些数据元素被放在括号内,并用逗号分隔;

参数a类型为int、long、short、char、byte、boolean、float或double数组。

对于类型是对象的一维数组或多维数组,需要使用下面这个方法:

public static String deepToString(Xxx[] a)

public static String deepToString(Xxx[][] a)

这些方法将在下面的例子使用。

4.7.2 排序

Ø 直接使用sort方法,来对数组做升序排序。sort方法常见的使用形式如下:

public static void sort(Xxx a[])

int a[] = new int[20];

Arrays.sort(a)

Ø 该方法用改进的快速排序方法对指定的数组a进行排序,其中数组a是类型为char、byte、short、int、long、float、double或者boolean的一个数组。

Ø sort方法还有另外一种常见的形式:

public static void sort(Xxx a[],int fromIndex,int toIndex)

Ø 这种形式只对数组a中指定范围内的元素(从a[fromIndex]到a[toIndex]之间的元素,其中不包含a[toIndex])排序。例:为整型数组排序

4.7.3 查找

public static int binarySearch(Xxx a[],Xxx v);

int a[] = new int[20];

Arrays.binarySearch(a, 10)

Ø 该方法用折半查找算法(关于算法,会在后续的课程里再介绍)在指定的数组a查找值为v的元素。其中数组a是类型为char、byte、short、int、long、float、double或者boolean的一个数组,v是与数组a的元素类型相同的值

Ø 该方法如果在数组a查找到值为v的元素,则返回该元素的下标;如果没有找到匹配的元素,则返回一个负值r,位置-(r+1)为保持数组有序时值为v的元素应该插入的位置

4.7.4 填充

public static void fill(Xxx a[],Xxx v)

int a[] = new int[20];

Arrays.fill(a, 1)

Ø 该方法用指定的值v来填充数组a,执行该方法的结果是:

Ø 数组a中所有元素的值都变成v

Ø 其中数组a是类型为char、byte、short、int、long、float、double或者boolean的一个数组。

4.7.5 复制

数组的复制一共有两种方法,分别是Arrays.copyOf以及System.arraycopy。

第一种复制的语法有如下两种方式:

public static Xxx[]copyOf(Xxx[] a,int length)

public static Xxx[]copyOf(Xxx[] a,int start,int end)

int a[] = new int[20];

int b[] = Arrays.copyOf(a, 5, 10)

返回与a类型相同的一个数组,其长度为length或者end-start,数组元素为a的值。

Xxx代表类型:int、long、short、char、boolean、float等

start:起始下标(包含这个值)

end: 终止下标(不包含这个值),这个值可能大于a.length,这种情况下结果为0或false

length:拷贝的数据元素长度,如果length大于a.length结果为0或false;否则数组中只有前面length个数据元素的拷贝值;

这里要注意,目标数组必须在调用arraycopy之前分配内存。如果长度大于原始数组的长度,那么多出来的元素将被赋上默认值,数组元素是数值型,那么多余元素将被赋值为0;数组元素是布尔型,则多余元素被赋值为false等等。相反如果长度小于原始数组的长度,则只拷贝原始数组最前面的数据元素。

例如:

int[] old1={1,2,3,4};

int[] old2={11,22,33,44,55};

//需要在程序顶部import java.util.Arrays;

old2=Arrays.copyOf(old1,old2.length);

System.out.println(Arrays.toString(old2));

输出:[1, 2, 3, 4, 0]

第二种方法的语法如下:

java.lang.System.arraycopy(from,fromIndex,to,toIndex,count)

该方法从数组from的索引fromIndex位置起,复制count个元素到数组to的从索引toIndex位置开始的地方。

from:任意类型数组

formIndex:原始数组from中待拷贝元素的起始下标

to:与from同类型的数组

toIndex:目标数组to放置拷贝元素的起始下标

count:拷贝的元素数量

这里要注意,目标数组必须在调用arraycopy之前分配内存。必须保证数组to的长度大于或等于数组from的长度,否则会报错。

例如:

int[] old1={1,2,3,4};

int[] old2={11,22,33,44,55};

System.arraycopy(old1,1,old2,0,3); System.out.println(Arrays.toString(old2));

输出:[2, 3, 4, 44, 55]

4.7.6 多维数组的使用

什么是多维数组?就是一个数组,里面的元素依然是数组。

举个例子吧,王母娘娘瑶池开蟠桃会,摆放几排桌椅,每排桌椅上都坐满了神仙。这个蟠桃会就是一个数组,数组里的元素是一排桌椅。而每一排桌椅又是一个数组,里面的元素是每一位神仙。

二维数组的定义语法如下:

数组元素类型 数组名[][] = new 数组元素类型[数组长度][];

例如:

//假设有12排桌椅,每排坐着12个神仙

ShenXian[][] panTaoHui = new ShenXian[12][12];

//依次类推,我们还定义三维数组,甚至更多维的数组

ShenXian[][][] panTaoHui = new ShenXian[12][12][12];

//这里我们可以看出,整个二维数组的标识类型,就是最底层元素的类型,因为其他上层的元素类型都是“数组”,不需要显式标识

//以上是针对对象的多维数组,为了方便我们理解,在实际编程中更常用的基础类型的多维数组,比如:

int a[][] = new int[10][5]

多维数组也可以使用枚举定义,同时完成了初始化的工作,例如:

ShenXian [][] panTaoHui =

{

{ new ShenXian("如来佛祖"), new ShenXian("观音菩萨")……},

{ new ShenXian("太上老君"), new ShenXian("太上老君")……},

{new ShenXian("赤脚大仙"), new ShenXian("太白金星")……}

}

或者:

int[][] a =

{

{1,2,3},

{4,5,6},

{7,8,9}

}

大家可以发现,任何级别的数组元素都是以逗号分隔,并且最后一个元素后面没有逗号,这个要记好。

访问二维数组的元素与一维数组类似,也是利用下标,即:

数组名[一维下标][二维下标]

例如PanTaoHui[0][1] 即为观音菩萨

a[0][1] 即为2

切记,每一层数组的下标都是从0开始,切记!

想快速打印一个二维数组的元素列表,可以调用:

System.out.println(Arrays.deepToString(数组名));

例如:System.out.println(Arrays.deepToString(a)),输出的就是[{1,2,3},{4,5,6},{7,8,9}]

4.7.7 不规则数组

上面前的都是规则的数组,那么什么是不规则的数组呢?

孙悟空大闹蟠桃会之后,想到花果山的孩儿们都没有吃过这么好的桃子呢,于是他找了几个麻袋,将桌上的桃子全都装了回去。我们假设他装了三个麻袋,但是每个麻袋里的桃子他可没有数过,应该不可能是相同的数量。

因此,我们可以这样理解,最底层的数组长度不相同的多维数组,即是不规则数组。换句话说,不规则数组就是不整齐的多维数组

Java中并没有针对多维数组的定义,这也造就了它在数组方面的优势:Java实际上只有一维数组,而数组的元素可以是任意长度的数组,因此我们可以通过这个特性来很方便的定义多维数组,以及不规则数组。

比如上例就可以写成:

Taozi [][] madai= new Taozi[3][];//3个麻袋

madai[0] = new Taozi[300];

madai[1] = new Taozi[600];

madai[2] = new Taozi[900];

最后再补充一点,多维数组(包括不规则数组),同样可以用循环来赋值和遍历。循环这里将在下面来详细讲解。

mybatisplus修改单个属性_第二节 官封弼马温——类的属性相关推荐

  1. 第三篇:属性_第二节:控件属性在页面及源码中的表示方式

    一.属性在页面及源码中的表示方式 认真地看看页面中声明控件的代码,你会发现控件属性在页面中的表示千变万化.我们看看下面这些: <%@ Page Language="C#" A ...

  2. iHRM 人力资源管理系统_第9章_文件上传与PDF报表入门_第二节_PDF报表入门

    iHRM 人力资源管理系统_第9章_文件上传与PDF报表入门_第二节_PDF报表入门 文章目录 iHRM 人力资源管理系统_第9章_文件上传与PDF报表入门_第二节_PDF报表入门 PDF报表入门 3 ...

  3. 代驾APP_第一章_项目环境搭建_第二节

    代驾APP_第一章_项目环境搭建_第二节 文章目录 代驾APP_第一章_项目环境搭建_第二节 1-11 创建bff-driver服务 一.创建项目 二.配置pom.xml文件 三.编写YML配置文件 ...

  4. css不换行属性_前端 | css display:flex 的六个属性你知道吗

    前言:display:flex 是一种布局方式.它即可以应用于容器中,也可以应用于行内元素.是W3C提出的一种新的方案,可以简便.完整.响应式地实现各种页面布局.目前,它已经得到了所有浏览器的支持. ...

  5. java 对象拷贝属性_使用Java对两个对象的属性进行拷贝

    最近和Java的反射打交道比较多一点,可能是因为自己以后的方向是架构师的缘故吧,他们主要搞业务.我能也就搞架构,整天画一些流程图. 虽然对于只有一年实习经验的我,不知道这样是否好,但是我还是那句话,不 ...

  6. php类3个属性是哪3种,PHP获取类私有属性的3种方法

    今天在推上看到一条获取php类私有属性的推文,感觉很有意思: 顺着推文联想,还有其他方式吗?经过自己的测试及网上答案,总结出三种方法: 1. 反射 反射可以获取类的详细信息,要获取私有属性的值,只需将 ...

  7. ios 监听一个控制器的属性_ios - kvo观察者示例(监听类的属性变化)

    首先创建Person分类 #import @interface Person : NSObject @property (nonatomic, copy) NSString *name; @prope ...

  8. mybatisplus修改单个属性_Mybatis Plus 中 参数传递的优化之路

    从项目开始使用 Mybatis Plus 到现在,对 Mapper 传递参数的方式做了多个版本的改进和优化.这篇文章主要讲解在改版和优化过程中遇到的问题,以及当时的一些想法. 第一版:单个参数传递 传 ...

  9. android中怎么保存checkbox中的checked属性_第二十四天HTML中的form表单

    form表单 用于收集用户信息,如:登录.注册等场景:所有要提交的数据都必须放在form标签中 action:提交地址.动作,与input标签中typy标签的submit属性相关联. ,提交地址是ac ...

最新文章

  1. android文本自动添加图片格式,Android中多行文本末尾添加图片排版问题的解决方法...
  2. Setting property 'source' to 'org.eclipse.jst.jee.server:hczm' did not find a matching property
  3. 程序员如何保持身心健康
  4. dns服务器漏洞修复,KB4569509:DNS 服务器漏洞 CVE-2020-1350 指南
  5. python3.8.2中文手册chm_springboot2.2.X手册:构建全局唯一的短链接数据中心
  6. nmap在kali的使用方法和常见命令(入门)
  7. node.js——麻将算法(二)赖子玩法
  8. 红外线遥控c语言程序,红外线遥控解码接收程序-c语言讲解学习.pdf
  9. 微软亚洲研究院20周年庆典:纳德拉致敬、沈向洋展望
  10. 赛灵思推7nm加速平台:面向所有场景、所有开放者,AI推理性能提升8倍
  11. HelloDjango 第 04 篇:Django 迁移、操作数据库
  12. 如何才是真正的大牛?遇见同行博士大牛,感慨自己太渣
  13. 理解伪元素:before和:after
  14. 计算机在线考试报名系统软件,全国计算机软考报名官网
  15. 网站服务器检测工具,服务器网络监测工具
  16. windows 中获取字体文件名
  17. 分享github好用的磁力站bt导航和阿里云盘导航、百度网盘搜索引擎导航
  18. Learning Deep Features for Discriminative Localization
  19. 数据库中的行式存储和列式存储
  20. Verilog语言学习

热门文章

  1. 单片机课程设计数字心率计_课程设计-基于单片机的数字人体心率计设计.doc
  2. 数据库设计范式实例解析
  3. U-Boot 之二 详解使用 eclipse + J-Link 进行编译及在线调试
  4. 题库练习1(单词长度、统计字符个数、)
  5. 网络安全 / crt、pem、pfx、cer、key 作用及区别
  6. MySQL / B + 树算法在 mysql 中能存多少行数据?
  7. 软件工程 / 为什么基于接口而非实现编程?
  8. 网络安全产品 / 相关产品简要说明
  9. ubuntu如何安装linux驱动程序,Ubuntu下如何安装驱动程序和应用软件?
  10. python gpiozero,树莓派远程GPIO调试(Python + pigpio版)