Java基础语法

//作者:苯环大叔·明太祖
//时间:2019年10月18号
//上一次修改时间:2019年10月23号
//内容:Java基础语法
//备注:部分笔记来源于网络,稍有改动,向原作者致敬。

Java基础语法

数据类型

整型

数据类型存储大小
byte(字节型)1字节/1B
short(短整型)2字节/2B
int(整型)(默认)4字节/4B
long(长整型)8字节/8B

注意:long类型数值后面最好要加上大写的L或l,别加l了,不明显。

补充:关于进制转换

int a = 0x0011;//十六进制赋值,a=17
int b = 0b1000;//Java7版本开始,二进制赋值,b=8
//不要用八进制

浮点型

数据类型存储大小
float(单精度)4字节/4B
double(双精度)(默认)8字节/8B

注意:float类型数值后面最好加上F或f。double类型数值后面可以根据个人喜好加上D或d。

补充:

a.可以使用十六进制表示浮点数值

//p表示后面是指数值,基数是 2
o.125 = 2^-3 = 0x1.0p-3

b.IEEE 754规范中溢出和出错的三种特殊值

分别是:正无穷大,负无穷大,不是一个数

Double包装类中对这三个数值有定义,源码如下

class public final class Double extends Number implements Comparable<Double>{
    //正无穷大
    public static final double POSITIVE_INFINITY = 1.0 / 0.0;
    //负无穷大
    public static final double NEGATIVE_INFINITY = -1.0 / 0.0;
    //不是一个数
    public static final double NaN = 0.0d / 0.0;
}

c.NaN的妙用

上面NaN不能用来检测一个值是否是一个数,因为NaN还可能是其它值,比如负数的平方根。

可以使用Double包装类内的isNaN()方法代替

//打印false,说明该判断失效,因为所有“非数值”的值都认为是不相同的
System.out.println(0.0d / 0.0 == Double.NaN);
//使用Double包装类的方法,判断是否是“非数值”,此时打印true
System.out.println(Double.isNaN(0.0d / 0.0));

d.关于四舍五入

金融计算无法接收舍入误差,二进制系统无法表示所有数,例如1/10。此时应该使用专门给大浮点数运算的类BigDecimal

//打印0.8999999999999999,而不是0.9
System.out.println(2.0-1.1);

字符型

char类型,强烈建议不要在程序中使用 char 类型 。

char a = 'a';
char b = 98;//98在ASCII码表中对应字符b

Java中采用Unicode编码规范,具体占用多大内存,我们要从编码规范的发展说起。

a.在Unicode之前,其实已经有了许多种不同的规范:美国的ASCII、西欧语言中的ISO8859-1、俄罗斯的KOI-8、中国的GB18030和BIG-5等。

b.全世界有上百种语言,中文把汉字编写到GB2312里,日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里,各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。

c.一开始,Unicode只是2个字节,不断地,更多的字符被编写到Unicode中。但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。现代操作系统和大多数编程语言都直接支持Unicode。ASCII编码是1个字节,而Unicode编码通常是2个字节。新的问题又出现了:如果统一成Unicode编码,乱码问题从此消失了。但是,如果你写的文本基本上全部是英文的话,用Unicode编码比ASCII编码需要多一倍的存储空间,在存储和传输上就十分不划算。

d.把Unicode编码转化为“可变长编码”的UTF-8编码。

补充:

Unicode的实现方式不同于编码方式。一个字符的Unicode编码是确定的。但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对Unicode编码的实现方式有所不同。

Unicode的实现方式也称为Unicode转换格式(Unicode Transformation Format,简称为UTF),目前主流的实现方式有UTF-16和UTF-8。随着Unicode通用字符集的扩充,进而出现了UTF-32,但是由于占用空间太大,目前很少有系统选择使用utf-32作为系统编码。

在计算机内存中,统一使用Unicode编码,当需要保存到硬盘或者需要传输的时候,就转换为UTF-8编码。

用记事本编辑的时候,从文件读取的UTF-8字符被转换为Unicode字符到内存里,编辑完成后,保存的时候再把Unicode转换为UTF-8保存到文件。

浏览网页的时候,服务器会把动态生成的Unicode内容转换为UTF-8再传输到浏览器。所以你看到很多网页的源码上会有类似的信息,表示该网页正是用的UTF-8编码。

布尔类型

boolean类型,只有两个值,true和false类型,默认值为false类型。

问题:boolean类型占用多大内存空间?

a.1bit,也就是1位,理由是boolean类型的值只有true和false两种逻辑值,在编译后会使用1和0来表示,这两个数在内存中只需要1位(bit)即可存储,位是计算机最小的存储单位。

b.1Byte,也就是1字节,理由是计算机处理数据的最小单位是1个字节。

c.4Byte,也就是4字节,理由来源是《Java虚拟机规范》书中描述:“虽然定义了boolean这种数据类型,但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令,Java语言表达式所操作的boolean值,在编译之后都使用Java虚拟机中的int数据类型来代替,而boolean数组将会被编码成Java虚拟机的byte数组,每个元素boolean元素占8位”。这样我们可以得出boolean类型占了单独使用是4个字节,在数组中又是1个字节。

总结:

根据http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html官方文档的描述:boolean: The boolean data type has only two possible values: true and false. Use this data type for simple flags that track true/false conditions. This data type represents one bit of information, but its “size” isn’t something that’s precisely defined.(布尔类型:布尔数据类型只有两个可能的值:真和假。使用此数据类型为跟踪真/假条件的简单标记。这种数据类型就表示这一点信息,但是它的“大小”并不是精确定义的。)

可以看出,boolean类型没有给出精确的定义,具体还要看虚拟机实现是否按照规范来,所以1个字节、4个字节都是有可能的。这其实是运算效率存储空间之间的博弈,两者都非常的重要。

变量与常量

变量的声明

变量分为全局变量和局部变量。全局变量在类中,与方法体同级,也称为属性变量或直接叫属性。局部变量存在于方法体内,生命周期较全局变量要短。但他俩的声明规则是一样的。

格式:修饰符 数据类型 变量名;

private int aa;
private transient double bb;
public boolean cc;

注意:

a.修饰符可以有多个,默认是default。

b.Java变量的基本命名法则:
1、只能以下划线、字母、美元符开头。(数字不能开头)
2、后面跟下划线、字母、美元符以及数字。
3、没有长度限制。(但也不能太长!)
4、对大小写敏感。(意思是大小写代表不同含义)

c.Java驼峰式命名法(约定俗成):
1、变量名必须为有意义的单词。
2、变量名如果只有一个单词,则小写。
3、如果有2个以及多个单词,则从第二个单词开始首字母大写。

d.实际开发中,个人是严格遵守阿里巴巴程序规范,养成良好的代码习惯。

Java关键字与保留字表:

关键字名称含义
abstract表明类或者成员方法具有抽象属性
assert用来进行程序调试
boolean基本数据类型之一,布尔类型
break提前跳出一个块
byte基本数据类型之一,字节类型
case用在switch语句之中,表示其中的一个分支
catch用在异常处理中,用来捕捉异常
char基本数据类型之一,字符类型
class
const保留关键字,没有具体含义
continue回到一个块的开始处
default默认,例如,用在switch语句中,表明一个默认的分支
do用在do-while循环结构中
double基本数据类型之一,双精度浮点数类型
else用在条件语句中,表明当条件不成立时的分支
enum枚举
extends表明一个类型是另一个类型的子类型,这里常见的类型有类和接口
final用来说明最终属性,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成员域的值不能被改变
finally用于处理异常情况,用来声明一个基本肯定会被执行到的语句块
float基本数据类型之一,单精度浮点数类型
for一种循环结构的引导词
goto保留关键字,没有具体含义
if条件语句的引导词
implements表明一个类实现了给定的接口
import表明要访问指定的类或包
instanceof用来测试一个对象是否是指定类型的实例对象
int基本数据类型之一,整数类型
interface接口
long基本数据类型之一,长整数类型
native用来声明一个方法是由与计算机相关的语言(如C/C++/FORTRAN语言)实现的
new用来创建新实例对象
package
private一种访问控制方式:私用模式
protected一种访问控制方式:保护模式
public一种访问控制方式:共用模式
return从成员方法中返回数据
short基本数据类型之一,短整数类型
static表明具有静态属性
strictfp用来声明FP_strict(单精度或双精度浮点数)表达式遵循IEEE 754算术规范
super表明当前对象的父类型的引用或者父类型的构造方法
switch分支语句结构的引导词
synchronized表明一段代码需要同步执行
this指向当前实例对象的引用
throw抛出一个异常
throws声明在当前定义的成员方法中所有需要抛出的异常
transient声明不用序列化的成员域
try尝试一个可能抛出异常的程序块
void声明当前成员方法没有返回值
volatile表明两个或者多个变量必须同步地发生变化
while用在循环结构中

变量的初始化

格式一:修饰符 数据类型 变量名 = 值;//定义同时初始化

格式二:变量名 = 值;//把定义好的变量直接赋值初始化

注意:

a.全局变量如果不初始化,是有默认值的,整型的为0,小数的为0.0,布尔型的为false,字符型的默认值是’\u0000’,表示每个二进制位都为0的Unicode字符,打印时什么也不打印。

b.局部变量声明后,如果想使用必须先初始化。

常量的声明与赋值

在Java中使用final关键字指示常量。关键字final表示这个变量只能被赋值一次。一旦被赋值之后,就不能够再更改了。习惯上,常量名使用全大写。

public static final String NAME = "苯环大叔";
public static final String LAST_NAME = "明太祖";

注意:

实际开发中,常在一个类或枚举中定义多个常量,其它类中使用起来也比较方便。

运算符与表达式

运算符分类

算术运算符:+,-,*,/,%,++,–

赋值运算符:=,+=,-=,*=,/=,%=

关系运算符:>,<,>=,<=,==,!=,instanceof

逻辑运算符:&&,||,!

位运算符:&,|,~,^,<<,>>,>>>

条件运算符:?:

运算符优先级

顺序优先级运算符运算方向
1()、[]、{}、.从左向右
2+(正号)、-(负号)、~、!、++、–、()(强制类型转换)、new从右向左
3*、/、%从左向右
4+(加号)、-(减号)从左向右
5<<、>>、>>>从左向右
6<、<=、>、>=、instanceof从左向右
7==、!=从左向右
8&从左向右
9^从左向右
10|从左向右
11&&从左向右
12||从左向右
13?:从右向左
14=、+=、-=、*=、/=、&=、|=、^=、~=、<<=、>>=、>>>=从右向左

规律:

单目运算符>双目算术运算符>双目位移>双目关系运算符>双目位运算符>双目逻辑运算符>三目运算符>赋值运算符

应用:

a.单目运算符++和–,数值放前放后不一样。i++则先表达式后自增,++i则先自增再表达式。

int a = 1;
int b = a++;
int c = ++a;
System.out.println(b);//打印1
System.out.println(c);//打印3

b.一个数左移一位相当于乘2,右移一位相当于除2。在进行2的次幂运算时,可以考虑位运算效率高的特性提高算法整体效率。

c.>>>无符号右移时,高位用0填充。>>右移高位用符号位填充,<<左移低位用0填充。

d.判断奇偶数。a&1,结果为0,a就是偶数,结果为1,a就是奇数。

e.求平均数 (x+y)/2 这样不行,要考虑 x+y可能超过int的范围,正确的方法是 (x&y)+((x^y)>>1)

f.有两个int类型变量x、y,要求两者数字交换,不用临时变量。x ^= y; y ^= x; x ^= y;(原理:b(ab)=a)。

g.取模 a % (2^n) 等价于 a & (2^n - 1)

h.求相反数(~x+1)。

i.双目逻辑运算符&&和||具有短路功能,运算符一侧判断完就能断定整个表达式的布尔值,另一侧就不用判断,短路功能由此得来。

注意:

尽量少写复杂的表达式,要提高代码的可读性。意思就是少装逼。

类型转换与类型提升

自动类型转换:低精度到高精度,部分转换可能会发生降低精度(精度丢失)。

double>float>long>int>其它

两个数值进行二元操作时,先要将两个操作数转换为同一种类型,然后再进行计算。

如果两个操作数中有一个是double类型,另一个操作数就会转换为double类型。
否则,如果其中一个操作数是float类型,另一个操作数将会转换为float类型。
否则,如果其中一个操作数是long类型,另一个操作数将会转换为long类型。
否则,两个操作数都将被转换为int类型。

注意:

a.char类型值是按照字符对应的ASCII码与整型类型运算的。

b.int转float,long转float,long转double类型时可能会发生精度丢失,这是因为存储结构造成的,具体可参考IEEE754标准。

//byte范围在-128~+127
byte b1 = 127;
byte b2 = 1;
int b3 = b1+b2;
//short范围在-32768~+32767
short s1 = 32767;
short s2 = 1;
int s3 = s1+s2;
char c1 = 'a';
int a = a + c1;
//混合运算
byte a = 1;
short b = 2;
int c = 3;
long d = 4;
float e = 5.0f;
double f = 6.0d;
double v1 = a + b + c + d + e + f;
float v2 = a + b + c + d + e;
long v3 = a + b + c + d;
int v4 = a + b + c;

强制类型转换:高精度到低精度,可能会发生数据错乱(有效数据丢失)。

//byte范围在-128~+127
byte b1 = 1;
byte b2 = 1;
byte b3 = (byte)(b1+b2);
//short范围在-32768~+32767
short s1 = 32767;
short s2 = 1;
short s3 = (short)(s1+s2);//会发生数据错乱

注意:

a.如果试图将一个数值从一种类型强制转换为另一种类型,而又超出了目标类型的表示范围,结果就会截断成一个完全不同的值,也就是丢失有效数据。

b.在C++或Java中,不要试图让boolean与任何类型进行强转,C++是防止发生错误,Java是肯定发生错误。

流程控制—条件语句

块作用域

块(block)就是用{}括起来的若干条语句,它确定了变量的作用域。

一个块可以嵌套在另一个块中。不能在嵌套的两个块中声明同名的变量。

注意:

在C++中,可以在嵌套的块中重定义一个变量。在内层定义的变量会覆盖在外层定义的变量。这样,有可能会导致程序设计错误,因此在Java中不允许这样做。

if语句

格式:if(condition){statement}

if(a>1){
    System.out.println("a大于1才执行");
}

if else语句

格式:if(condition){statement1}else{statement2}

if(a>1){
    System.out.println("a大于1才执行");
}else{
    System.out.println("a小于等于1才执行");
}

if else嵌套链语句

格式:

if(condition1){statement1}else if(condition2){statement2}else if(condition3){statement3}…

if(a<20){
    System.out.println("a小于20才执行");
}else if(a<40){
    System.out.println("20<=a<40才执行");
}else if(a<60){
    System.out.println("40<=a<60才执行");
}else{
    System.out.println("a大于等于60才执行");
}

switch语句

格式:

switch(表达式){

case1:语句1;break;

case2:语句2;break;

default:默认语句,一般填报错语句

}

switch (a){
    case 10:
        System.out.println("a="+a);
        break;
    case 20:
        System.out.println("a="+a);
        break;
    case 30:
        System.out.println("a="+a);
        break;
    default:
        System.out.println("有一些错误发生");
}

注意:

a.用switch case能表达的,用if else一定能表达。用if else能表达的,用switch case不一定能表达。平时推荐使用if语句。

b.case标签可以是类型为char、byte、short或int的常量表达式、枚举常量,从JavaSE7开始,case标签还可以是字符串字面量。

流程控制—循环语句

while循环

格式:

while(布尔表达式){循环体代码}

while(true){
    System.out.println("这是一个死循环");
}

注意:

不要忘了加上跳出循环的条件,否则死循环会导致严重的程序执行错误。break语句可以直接跳出循环。

do while循环

格式:

do{循环体代码}while(布尔表达式);

int a = 1;
do {
    System.out.println(a);
    a++;
}while (a<=3);

注意:

a.千万别漏了while语句括号后面的分号。

b.与while语句的区别就是dowhile语句先执行一次再判断,也就是至少执行一次循环体。

c.break语句能直接跳出循环。

for循环

格式:

for(初始状态(可不写);布尔表达式;改变状态(可不写)){循环体代码}

int sum = 0;
for (int i=1;i<=100;i++){
    sum += i;
}
System.out.println("1到100的和为:"+sum);

foreach循环

该循环是for循环的增强版,在Java8才有的新特性。

格式:

for(元素类型 元素名称 : 要遍历的数组实体(集合对象)){//循环体//使用元素名称可以访问单个元素}

int[] arr = {1,2,3,4,5};
List<String> list = new ArrayList<String>();
list.add("唐太宗");
list.add("宋太祖");
list.add("元世祖");
list.add("明太祖");
for(int i:arr){
    System.out.println(i);
}
for(String str:list){
    System.out.println(str);
}

扫描仪与输入

Scanner类

1.next()与nextline()方法

区别:

next()方法只读取输入到第一个空格。它不能读两个由空格隔开的字符串。此外,next()在读取输入后将光标放在同一行中。(next()只读空格之前的数据,并且光标指向本行)。

nextLine()方法读取输入,包括所有空格和空格连接的字符串,除了换行(即读到行尾)。读取输入后,nextLine()将光标定位在下一行。

import java.util.Scanner;
class TestScanner{
    public static void main(String[] args){
        Scanner scanner = new Scanner(System.in);
        String str = scanner.nextLine();//输入555 abc +-*/
        System.out.println(str);//打印555 abc +-*/
        String str2 = scanner.next();//输入555 abc +-*/
        System.out.println(str2);//打印555
    }
}

2.nextXxx()指定类型系列方法

nextInt,nextBoolean,nextDouble……,意思为只能输入指定类型的数据。

Scanner scanner = new Scanner(System.in);
int i = scanner.nextInt();//只允许输入整型数字
boolean b = scanner.nextBoolean();//只允许输入布尔值
double d = scanner.nextDouble();//只允许输入双精度小数

注意:

如果输入的与对应类型不同的值,或者值的范围超过类型内存模型大小,会抛出异常:java.util.InputMismatchException。

3.hasNext()方法系列

除了hasNext(),还有hasNextInt(),hasNextBoolean,hasNextDouble……,意思为判断是否还有输入或是否还有对应类型的输入。返回值为布尔值。

Scanner scanner = new Scanner(System.in);
boolean b1 = scanner.hasNext();//输入有数据即返回true,不输入则返回false。
boolean b2 = scanner.hasNextInt();//输入整型数据即返回true,否则返回false。
boolean b3 = scanner.hasNextDouble();//输入双精度小数数据即返回true,否则返回false。
System.out.println(b1);
System.out.println(b2);
System.out.println(b3);

4.Scanner类也能读取文件内容,可参考IO流操作。

格式化输出

print()与println()函数

print为一般的标准输出、println为一般的标准输出最后输出一个换行(自动换行)。

print()加了转义符\n也可以换行。打印等同于println()。

System.out.print("666");
System.out.println("777");
System.out.print("888\n");

printf()函数

printf()为格式化输出,自Java5开始,沿用C语言库函数中的printf()函数。

double x = 10000.0/3;
//占位符%f绑定
System.out.printf("x的值为:%f\n",x);//打印x的值为:3333.333333
//值占9个字符空间,保留两位小数,位数不足的,前面补空格
System.out.printf("x的值为:%9.2f\n",x);//打印x的值为:  3333.33
//整数位以逗号隔开
System.out.printf("x的值为:%,8.2f\n",x);//打印x的值为:3,333.33

常用的占位符还有:

占位符意义
%s字符串
%c字符
%b布尔值
%h哈希散列码
%%百分号
%n换行

函数与方法

函数的定义

格式:

修饰符 返回值类型 方法名(参数类型1 形参1,……) 抛出的异常{方法体}

class Test{
    public static void findPeople(int id,String password) throws Exception{
        System.out.println(id+""+password);
    }
    public String getPassword(){
        return password;
    }
}

函数的调用

格式:

1.本类调用,直接调用。

findPeople(1,123456);//无返回值
String password = getPassword();//有返回值

2.对象调用,用对象调用。

class Demo{
    Test test = new Test();
    test.findPeople(1,123456);
    String password = test.getPassword();
}

3.类调用,静态方法直接使用类调用(类加载机制)。

class Demo{
    Test.findPeople(1,123456);
}

注意:

a.函数名要遵守驼峰命名法规范,尽量用有意义的单词命名,只有一个单词全小写,大于1个单词则从第二个单词开始首字母大写。

b.调用有参函数时,由于有重载机制,传递的实际参数必须要跟调用的函数的形参顺序、类型、个数一致。

c.关于传参时的值传递机制,Java传递普通类型都是传递值的副本,传递对象类型是传递的引用的副本,但指向的是同一个对象,类似于C++的指针。

函数的递归

1.一个函数调用了它本身。

2.大问题分解为很多小问题,小问题跟大问题解决办法相同。这时候可以使用递归。

3.出现无穷递归,需要为函数添加一个出口(递归头)。

注意:

优点:程序简单

缺点:如果递归不能使问题简化并最终收敛到基础情况,就有可能出现无限递归,会导致一个 StackOverflowError(栈溢出)的错误。递归调用会占用大量的系统堆栈,内存耗用多,在递归调用层次多时会比循环慢的多。

使用注意:当递归方法能更自然地反映问题、易于理解和调试、并且不强调效率问题时,可以采用递归。要求高效能的情况下尽量避免使用递归。

递归与迭代的区别:

a.递归常被用来描述以自相似方法重复事物的过程,在数学和计算机科学中,指的是在函数定义中使用函数自身的方法。(A调用A)。迭代是重复反馈过程的活动,每一次迭代的结果会作为下一次迭代的初始值。(A重复调用B)

b.递归是一个树结构,从字面可以其理解为重复“递推”和“回归”的过程,当“递推”到达底部时就会开始“回归”,其过程相当于树的深度优先遍历。迭代是一个环结构,从初始状态开始,每次迭代都遍历这个环,并更新状态,多次迭代直到到达结束状态。

c.迭代可以转换为递归,但递归不一定能转换为迭代。

应用:

1.求1到100累加和。2.求阶乘。3.斐波那契额数列。4.汉诺塔。5.兔子问题。

//递归求阶乘
public static int factorial(int a){
    if (a == 1){
        return 1;
    }
    return a*factorial(a-1);
}
//迭代求阶乘
public static int factorial2(int a){
    int result = 1;
    for (int i=2;i<=a;i++){
        result *= i;
    }
    return result;
}
//斐波那契数列:数列从第三项开始,每一项都等于前两项之和。如1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144,…
//数学定义(递归):F0=0,F1=1,Fn=Fn-1+Fn-2(n>=2,n∈N*)
class Fibonacci{
    public static void main(String[] args) {
        System.out.println(factorial(4));
        System.out.println(iteration(4));
    }
    //递归求斐波那契数列
    public static int factorial(int n){
        if (n == 0||n == 1){
            return n;
        }else {
            return factorial(n-1)+factorial(n-2);
        }
    }
    //迭代求斐波那契数列
    public static int iteration(int n){
        int first = 0;
        int second = 1;
        int result = 0;
        if (n == 0||n == 1){
            return n;
        }else {
            for (int i=2;i<=n;i++){
                result = first + second;
                first = second;
                second = result;
            }
            return result;
        }
    }
}
//汉诺塔问题
class Hannoi {
    public static void main(String args[]){
        System.out.println("请输入要移动的块数:");
        Scanner sc=new Scanner(System.in);
        int n=sc.nextInt();
        move(n,'a','b','c');
    }
    public static void move(int n,char a,char b,char c){
        if(n==1){ //当n只有1个的时候直接从a移动到c
            System.out.println(a+"-->"+c);
        }else{
            move(n-1,a,c,b);
            System.out.println(a+"-->"+c);
            move(n-1,b,a,c);//第n-1个移动过来之后b变开始盘,b通过a移动到c
        }
    }
}

函数的回调

把函数当做函数的参数来调用。调用参数的时候,相当于调用函数。这就是函数的回调。

由于在Java语言中无法传递函数的机制,接口就成了传递函数的工具。在Java8开始引入了函数式编程,Java语言进一步优化。

1.同步回调

同步回调即,从主线程自调用回调函数起,要等待回调函数执行完,然后继续执行主线程任务。

public class Tools {
    /**
     * 测试函数使用时间,通过定义CallBack接口的execute方法
     * @param callBack
     */
    public  void testTime(CallBack callBack) {
        //测试起始时间
        long  begin = System.currentTimeMillis();
        //进行回调操作
        callBack.execute();
        //测试结束时间
        long  end = System.currentTimeMillis();
        //进行回调操作
        System.out.println("[use time]:"  + (end - begin));
    }
    public static void main(String[] args) {
        Tools tool = new  Tools();
        tool.testTime(new CallBack(){
            //定义execute方法
            @Override
            public void execute(){
                //这里可以加放一个或多个要测试运行时间的方法
                for (int i=1;1<10000;i++){
                    System.out.println("耗时间的操作");
                }
            }
        });
    }
}
interface CallBack{
    //执行回调操作的方法
    void  execute();
}

2.异步回调

异步回调意味着新线程的开辟,主线程不必等待调用的回调函数执行完,创建完新线程和任务后,自己向下继续执行。可以给回调函数设定消息通知机制主线程执行完毕。

class CallBack {
    //测试回调,主线程
    public static void main(String[] args) {
        myNeed();
    }
    public static void myNeed(){
        //开启线程--->点外买
        new Thread(new Runnable() {
            @Override
            public void run() {
                //带什么外卖
                String food = "你好,请帮点一份蛋炒饭盖饭,要辣,要放鸡精,不放味精,盐要低钠盐,还要多放点葱花";
                //下单
                takeouts(food);
            }
        }).start();
        //玩游戏去
        playGames();
    }
    public static void playGames() {
        System.err.println("我玩游戏去了");
    }
    /**
     * 外卖送到门外,敲门提示我外卖到了,叫我去拿外卖----这个方法就是所谓的--->回调函数
     */
    public static void callback(String message) {
        //这里就是需要等待之后才能进行的后续业务逻辑
        System.err.println(message);
    }
    //外卖耗费时间与送到通知
    public static void takeouts(String food) {
        // 模拟带外卖需要的时间
        for (int i = 0; i < 10000; i++) {
            for (int j = 0; j < 100; j++) {
                for (int k = 0; k < 10000; k++) {
                    for (int l = 0; l < 100; l++) {
                    }
                }
            }
        }
        // 外卖送到了门口,敲门
        String message = "你的外卖到了";
        callback(message);
    }
}

3回调函数的应用

Spring框架的AOP编程思想。

4.代理模式和回调函数的区别:

a.代理模式需要创建接口实现类,并放入代理类中,隔离性更好,扩展性好。

b.回调函数不需要创建接口实现类,编写方便。

方法的重载

一个类中可以定义有相同的名字,但参数不同的多个方法。调用时,会根据不同的参数表选择对应的方法。

只有返回值不同不构成方法的重载。只有形参的名称不同,不构成方法的重载。

注意:要区分方法的重写(覆盖)。

class Test{
    public void getPeople(String name,int id){}
    public void getPeople(String name,int id,int age){}
}

面向过程编程思想

函数是最基本单位,整个程序是由一个个函数调用组成。

面向对象编程思想

类是最基本单位,方法是属于类和对象的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值