注释

含义:程序中的注释,用来说明某段代码的作用,或者说明某个类的用途、某个属性的含义、某个方法的功能·,方法参数和返回值数据类型、意义等。简单来说就是对类中的代码进行说明解释

作用:注释可以增加代码的可读性,当然程序员最讨厌的就是写注释和看没有注释的代码,所以注释可以让自己或者他人更好的解析自己编写的代码,同时有利于后期对系统的维护和升级。

  • 单行注释
  • 多行注释
  • 文档注释

注释代码不会被代码编译,也不会对程序运行产生影响,当然在·单行注释中也有例外,在单行注释会进行说明。

单行注释

public class Test{
    // 主方法 程序的入口 mian
    public static void main (String[] args){
        System.out.print("hello");
    }
}

其中// 后面就代表的是注释部分,并不会对源代码的的编译运行有任何影响

特殊情况
public class Test{
    //主方法 程序的入口 mian
    public static void main (String[] args){
        // 定义一个int类型的变量 a 并赋值2
        int a = 2;
        // /u000d a = 3;
            System.out.println("a:"+a);
    }
}

在一个程序中,按照注释不会被编译的说法,a的值应该为2,但事实上a输出的结果为3,这是因为 /u000d类似于换行,这就使得 a=3这一行代码被换到了下一行,而// 是单行注释,不在该行的代码会将不会被注释,这就使得a的重新赋了一个3的值

多行注释

/*
类名:Test
作用:多行注释测试类
日期:2020-08-03
作者:凉拌小番茄
*/
public class Test{
    public static void main (String[] args){
        System.out.print("hello");
    }
}

/* */表示多行注释,多行注释可以单行注释,也可以多行注释,但不会出现单行注释的情况。但值得注意的是多行注释不能嵌套多行注释,不然会编译报错,就是不会在多行注释当中在进行多行注释,但可以进行单行注释//

文档注释

文档注释:/** */,可以生成API文档(说明文档,对Java程序进行解释说明)

在生成API文档的时候,如果可以得到耕读的详细细信息 可以使用javadoc标记,常用的标记有:

  • @author:作者
  • @version:版本
  • @since:jdk版本
  • @deprecated:不推荐使用的方法、过时的方法。
  • @param:方法的参数类型。
  • @return:方法的返回类型。
  • @see:用于指定参考的内容。
  • @exception:抛出的异常。
  • @throws:抛出的异常,和exception同义
  • @see:关联其他类
package com.briup.day03;

/**
 * 文档注释测试类,利用文档注释,结合javadoc命令,可以生成API说明文档
 * @author 凉拌小番茄
 * @version 1.0
 * @since JDK1.8
 * @see com.briup.day03.Comment03
 */
public class Comment04 {

    /**
     *  类中的属性,表示问好语句的模式
     *  0 - hi xxx
     *  1 - hello xxx
     *  默认是模式为 1
     */
    public int mode = 1;

    /**
     * 返回向指定人问好的语句
     * @param name  用户姓名,向其问好
     * @return  问候的语句
     * @exception RuntimeException 运行时,mode值不是0或者1,会出现异常
     */
    public String sayHello(String name)throws RuntimeException{
        if (mode == 0){
            return "hi! "+name;
        }
        else if(mode == 1){
            return "hello! "+name;
        }
        else{
            throw new RuntimeException("error mode");
        }
    }

    /**
     * @deprecated 测试方式,已经废弃
     */
    public void test(){}

}

生成对应doc文件的命令

javadoc -d api -author -version src/*.java

javadoc -d api -sourcepath src -subpackages com -author -version

-sourcepath 指定源代码存放的位置
-subpackages 指定要递归查找的包的名字

符号

分号

在Java中,一句代码的结束是用英文分号来表示。

需要使用分号的代码语句有:

  • 包的声明语句
  • 类的引入语句
  • 属性的声明语句
  • 方法中要执行的代码

当然也有不需要加分号的代码

  1. 类的声明
  2. 方法的声明
  3. 代码块的声明

简单来说就是花括号{}后面不需要跟分号来代表语句结束。

空白

在代码中,可以使用空格,tab、换行(\n),回车(\r),并且对代码没有影响

,总体就是为了让代码更加整齐,美观,方便阅读等,写代码要优雅

注意,不可以使用这些空白来分割单词或关键字

标识符

在Java中,给类,方法,变量起的名字就是标识符。

命名规则

  • 标识符可以由字母、数字、下划线_ 、美元符号$组成
  • 标识符开头不能是数字
  • 标识符中的字符大小写敏感
  • 标识符的长度没有限制
  • 标示符不能使用java中的关键字或保留字

当然标识符满足这些规则就可以在代码中正常使用,但还有一些推荐规则,还是那句话,写代码要优雅

推荐规则

  • 尽量使用有意义的名字,尽量做到见名知义。

例如,int numOfStudnet = 10; String userName = “tom”;

  • 包名 最好是域名倒过来,要求所有的字母小写

package com.briup.test;

  • 类和接口,首字母大写,如果是俩个单词,第二个单词的首字母大写(驼峰命名规则)

例如,public class Account{} ,public interface AccountBase{}

  • 方法和变量,首字母小写,如果是俩个单词,第二个单词的首字母大写(驼峰命名规则)

例如,public void getStudentName(){} , int personNum = 1;

  • 常量,全部字母大写,如果是俩个单词,使用下划线分隔

例如,public static final int MAX_NUM = 10;

在计算机中只要加法运算,没有减法的算,我们所知的减法其实是加上它的相反数(加负数)

原码

最高位表示符号位,其中1代表负号,0代表正号,其他位存放该数的二进制的绝对值。

以1010为例

最高位(第一位)的1代表的就是负号,真正的值是后三位,换算为十进制为2,所以1010表示的是十进制的-2.

原码的计算,正数之间的运算不会出错,但是正数与负数相加,就引起错误

0001 + 1001 = 1010 (1 +(-1)= -2)

而这就需要反码

反码

反码:
正数的反码还是等于原码
负数的反码就是他的原码除符号位外,按位取反。

相加的结果是一个反码,不能够直接转十进制需要将反码转成原码才能转成10进制

反码解决了相反数相加不为零的问题

0001 + 1110 = 1111 ( 1 +(-1)= - 0)

但反码还是存在一定的问题,就是两个负数相加时,结果也会出错

1110(-1)+ 1100(-3)= 1010(-5)

这时候就需要补码

补码

正数补码与原码一样
负数补码是反码末位 +1

计算机里面存储的就是补码, 运算也是采用补码运算

注意,java中,正数补码按位取反(包括符号位)在加1,就是对应的负数,负数的补码按位取反再加1,就是对应的正数

基本类型

  • byte
  • short
  • int
  • long
  • float
  • double
  • char
  • boolean

这八种数据类型表示了Java中最基本的数据的结构

boolean

布尔类型占1个字节(8位),它的的值,必须是true或者false,在JVM中会转换为1(true)或者0(false)

char

char类型占2个字节(16个比特位),用来表示字符,String表示字符串,时类类型。一个String由0~n个char组成,字符char使用单引号表示,字符串String使用双引号表示。

//单个字符都可以正常显示,单个字符就是不论是什么,只要在编码表中都对应一个编码值,那么就是单个字符
char a = 'a';
char a = '我';
char a = '1';
//除此之外,还可以用其他方法表示
//使用Unicode编码值表示字符a
char c = '\u0061';
//0x开头的数字位十六进制,使用十六进制表示字符a(0x开头代表16进制)
char c = 0x0061;     
//使用十进制数字表示字符a
char c = 97;
//0开头的数字为八进制,使用八进制表示字符a(0开头代表八禁止)
char c = 0141;        

//注意:一个中文汉字就是一个字符
char c = '中';

除了这些还有一个特殊的字符,例如

常用转义字符

效果

使用

\n

换行符,将光标定位到下一行的开头

‘\n’

\r

回车,把光标移动到行首(和环境有关)

‘\r’

\t

垂直制表符,将光标移到下一个制表符的位置

‘\t’

\\

反斜杠字符

‘\’

\’

单引号字符

‘’’

\"

双引号字符

‘"’

整型

  • byte 8位、 1字节 范围:负2的7次方~2的7次方减1
  • short 16位、2字节 范围:负2的15次方~2的15次方减1
  • int 32位、4字节 范围:负2的31次方~2的31次方减1
  • long 64位、8字节 范围:负2的63次方~2的63次方减1

有符号整数把二进制数的首位作为符号数,当首位是0时,对应十进制的正整数,当首位是1时,对应十进制的负整数。

0000 0000 0000 0001 : 1

1000 000 0000 0001: -1

//类型的转换,在没有类型声明的情况之下,默认是int的类型
/*
byte<short<int<long
其中大类型不能向小类型之间转换,不然出现精度丢失的错误,但小类型可以向大类型直接转换
*/
byte a = 3;
//在这里就会报错,因为1默认的类型是int类型,int的类之间转换为byte类型
byte b = a+1;
//这里编译不会报错,因为在前面加了一个(byte)强换类型,但运行结果可能会与预期结果不符,这是因为a是变量
byte b =(byte)a+1;
//这里系统不会报错,因为对于这样的定值,编译的时候会自动运算,只要在byte的取值范围之内都不会报错
byte c = 1+1;
//在这里,编译也会报错,因为byte是1个字节,取值范围-127~128,超过这个范围,系统就会报错
byet d = 200;
//在这里编译不会报错,但运行结果会与预期结果不符,这是因为超过了byte的范围,超出范围的部分会被舍弃,剩余部分也会经过计算机补码运算规则进行计算。
byte e = (byte) 200;

Java中的=是赋值的意思,将左边的值赋予右边

四种整型类型的声明:

byte  a1 = 1;	(内存中占8位) 1字节
short a2 = 1;	(内存中占16位)2字节
int   a3 = 1;	(内存中占32位)4字节
long  a4 = 1L;	(内存中占64位)8字节

使用long类型数据的时候,后面要加大写L或者小写l,建议加上大写的L,因为小写的l和数字1很像似。

浮点型

float和double都是java中的浮点型,浮点型可以用来表示小数,它们的二进制表示方式和整型不同 35 * 10^(-1),因为计算机中没有小数的概念,在计算机中默认的就是科学计数法的形式

float是32位, 1bit(符号位) 8bits(指数位) 23bits(尾数位)
double是64位 1bit(符号位) 11bits(指数位) 52bits(尾数位)

float和double的精度是由尾数的位数来决定的。浮点数在内存中是按科学计数法来存储的.

数值 = 尾数 × 底数 ^ 指数,(附加正负号)

  • float的精度为6 ~ 7位左右有效数字 (2 ^ 23 = 8388608)
  • double的精度为15 ~ 16位左右有效数字 (2^52 = 4503599627370496)

俩种浮点型数据的声明:

//后面加f或者F
float f = 10.5f;
//后面加d或者D,默认double
double d = 10.5d;

浮点型的二进制形式:可以使用API提供的方法获取浮点数的二进制形式

float f = 10.5f;
//将f的值转化为int类型
int b = Float.floatToIntBits(f);
System.out.println(Integer.toBinaryString(b));

浮点型的默认类型是double,对于给出一个字面值是10.5的数据,在没有指明这个数据是什么具体的类型的情况下,那么java中默认认为是double类型。

例如,

//编译通过
//字面值1.5默认类型是double
double d = 1.5;
double d = 1.5d;

//编译报错
//字面值1.5默认类型是double
//double和float的精确度不一样
float f = 1.5;

//f2编译通过,因为字面值1的类型是int
//f3编译报错,因为字面值1.5的类型是double
float f1 = 10.5f;
float f2 = f1+1;
double f3 = f1+1.5 +(-0.5);

浮点型的精度丢失:

例如,

System.out.println(1.0-0.66);
//输出结果: 0.33999999999999997

Java中的浮点数类型float和double不能够进行精确运算,虽然大多数情况下是运行是正常的,但是偶尔会出现如上所示的问题。

这个问题其实不是java语言的bug,而是因为计算机存储数据是二进制的,而浮点数实际上只是个近似值,所以从二进制转化为十进制浮点数时,精度容易丢失,导致精度下降。


要保证运行结果的精度,可以使用BigDecimal类:

//add方法 +
//subtract方法 -
//multiply方法 *
//divide方法	/
BigDecimal d1 = BigDecimal.valueOf(1.0);
BigDecimal d2 = BigDecimal.valueOf(0.66);
double result = d1.subtract(d2).doubleValue();
System.out.println(result);
//输出结果:0.34

BigDecimal是java.math包中的类,使用时需要import导入

作业:

1.请编写一个类,并生成相对应API文档,需要在文档上体现作者和版本信息

package com.briup.test;
/**
    @author 凉拌小番茄
    @version 1.0
    @since JDK 1.8
 */
public class Test{
    /**
     * main方法,程序入口,写法固定
     * @param args  程序入口参数,如果需要,运行时可以给main方法进行传参
     */
    public static void main (String[] args){
        /**
        定义一个数组 arr
         */
        int arr[]={2,4,1,3,7};
        /**
        外层循环 遍历次数
         */
        for(int i=0;i<arr.length;i++){
            /**
            内部循环 遍历数组指定元素
             */
            for(int j=0;j<arr.length-i-1;j++){
                /**
                判断语句 两个元素比较 找出最小值
                 */
                if(arr[j]>arr[j+1]){
                    int temp=arr[j+1];
                    arr[j+1]=arr[j];
                    arr[j]=temp;
                }
            }
        }
        /**
        增强for循环 遍历排序好的数组 将数值打印出来
         */
        for(int s:arr){
            System.out.print(s+" ");
        }
    }
}

javadoc -d api -author -version Test.java -encoding utf-8

2.以下代码有没有问题,如果有问题,请指出来

long a = 1L;
int b = a + 1;
从long转换到int可能会有损失

3.以下代码是否报错,请阐述原因,怎么修改,修改后结果是多少,为什么?
byte b = 130;

byte的取值范围在-128~127之间,130超过这个范围,编译报错

修改方法:

1、将变量b定义为short 或者int 这些范围更广泛的类型 b=130

2、强制转换为byte类型 byte b =(byte) 130;此时b最终输出的值为-126

4.java中基本数据类型是什么,每一个在内存中占多少比特位,多少字节

类型 比特位 字节

boolean 8 1

char 16 2

byte 8 1

short 16 2

int 32 4

long 64 8

float 32 4

double 64 8

5.变量的作用是什么

变量的作用就是用来接收、保存、传递、操作对应的数据的。

附加题
构建两个线程A,B,让两个线程交替输出 A1,B2,A3,B4 …
A线程输出 A开头的数据
B线程输出 B开头的数据

package com.crm.systemset.controller;

/**
 * 创建两个线程和一个标志位
 *  如果标志位为true,A执行,执行完后并且将标志位改为false
 *  如果标志位为false B执行,并且完后并且将标志位改为true
 *  同时标志位要被两个线程共享
 */
public class A {

    /**
     * 用来 ++
     */
    int a = 0;

    /**
     * 标志位
     */
    boolean flag = true;

    /**
     * 锁对象,两个线程使用同一个锁对象
     */
    Object object = new Object();

    public void print(){
     // 加锁
      synchronized (object) {
          try {
              // 获取当前线程的名字
              String name = Thread.currentThread().getName();

              // 如果 flag == false 同时正在执行的线程为 A,那么就释放锁对象,让该线程进入等待
              if (!flag &&  name.equals("A") ) {
                 object.wait();
             // 如果 flag == true 同时正在执行的线程为 B 那么就释放锁对象,让该线程进入等待
             } else if(flag && name.equals("B")) {
                 object.wait();
             }
              // 打印线程名  + 数值变化
              System.out.println(name + (++a));
              // 为了更加显示效果,将当前线程休眠1s 不释放锁
              Thread.sleep(1000);

              // 执行完成后,将flag 变成相反的值
              flag = !flag;

              // 唤醒等待的线程
              object.notifyAll();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
    }

    public void start() {
      // 创建线程,Thread()里面采用拉姆达表达式,并且将线程的名字设置为A
      Thread t1 =  new Thread(() -> {
           while(true) {
               print();
           }
        },"A");
      // 启动线程
      t1.start();

      // 创建线程,Thread()里面采用拉姆达表达式,并且将线程的名字设置为B
      Thread t2 =  new Thread(() -> {
            while(true) {
                print();
            }
      },"B");
      // 启动线程
      t2.start();
    }
    public static void main(String[] args) {
        // 创建对象
        A a = new A();

        // 调用方法
        a.start();

    }

}