Java使用笔记

运行环境

任何语言,都需要有其开发运行环境

jre: java runtime environment java运行环境
包括jvm和java程序所需的核心类库等,
如果想要运行一个开发好的java程序,只需要安装jre即可

jdk:java development kit java开发工具包
jdk提供给java开发人员使用,包含了jre
也包含了一些开发工具:编译工具java.exec,打包工具jar.exe

总结:使用jdk开发完的java程序,交给jre运行

Java 文件

java 的可以执行文件”.class”

【windows】
命令行中设置临时环境变量

set Path=E:\jdk\bin\;%path%

【linux】
$path=$PATH:xxxx

java中无论从jar包加载还是从.class文件加载,都有一个classpath的概念,类似于PATH。
系统会从当前路径下寻找,然后在PATH中寻找,都没有则会报错
classpath也一样
不同的是,PATH只能包含目录,classpath可以包含jar包

java.lang.NoClassDefFoundError错误:

  • 没有在classpath中忘掉了需要的jar包

classpah 的作用就是告诉系统java运行环境,告诉java虚拟机到哪里去寻找需要的jar包或文件

classpath 中需要注意的:

  1. classpath告诉jvm到指定目录下寻找需要的jar文件,
  2. jvm默认只会寻找classpath中的路径
  3. 如果classpath路径后加了”;”,则jvm在寻找完指定路径后,会搜索当前路径;
  4. 如果不想让jvm自动去寻找当前路径,则不需要在最后的路径后添加”;”,
  5. 如果需要jvm在当前路径寻找,又在指定的其他路径寻找,classpath=.;xxxx
    这样,就会现在当前路径寻找,再到指定路径寻找
  6. 添加以后的classpath,

windows下想已有的classpath中添加临时的路径,
set classpath=.;%classpath%

每个.java文件中,可以包含多个class ,但是每个class后面的名称都不能相同;

  • 一个.java文件中,只能有一个public修饰的class
  • 为方便,每个.java文件的名称都必须与public的类名称完全一致

如果java原文件中包含了package信息,例如com.data.data,则这个原文件要放在相应的目录下,

  • 如:person.java使用了package com.data.data,
  • 那么,person.java应该放在src/com/data/data目录下

java生成的.class文件也会遵循类似的目录结构和命名方式

Java程序中源代码文件那么多,编译之后生成那么多.class文件,怎么方便管理呢?

jar工具,用来给我们的程序打包,

  • 打包之后会生成一个.jar文件,
  • 这个文件跟zip文件的结构是一样的,可以用解压工具打开,方便管理。
    1
    jar -cfv test.jar  Test.class
    java 包

  • 有层次关系
  • 包嵌套的层次可以保证包名的唯一性,
  • 建议用Internet域名的倒序作为包的前缀
    • lzy.com –> com.lzy.mypackage,
  • 包名用小写字母表示
  • 包名与文件系统的目录结构一一对应
  • 要使java知道包在文件系统中的地址,需要修改classpath(类路径)

在包中添加类

  • 只需在程序的最前端加上
    package PACKAGE_NAME

Java注释

1
2
3
4
5
//单行注释
/**/多行注释

/** 文档注释
*/

注:文档注释可以通过javadoc程序自动提取生成相关说明文档
类似于python中
“””
“”” 三引号中的紧跟在函数或类下面的说明文档

注释很重要,
与人方便,于己方便

代码仅仅是思想的一种体现形式

想好了可以先用中文或更容易表现的形式展示出来。

类的形式就是一个字节码,给计算机看的

常量

整数常量
小数常量
布尔(boolean)常量:
字符常量 –> 用’’单引号标识的,单个/一个[数字(0-9)和字母,符号]
字符串常量 –> 用””双引号标识的
null常量

整数:有四种表现形式
二进制:0,1,满2进1
八进制:0-7,满8进1,用0开头表示
十进制:0-9,满10进1
十六进制:0-9,A-F,满16进1,用0x表示

进制“一种计数的形式”

变量

内存中的一个存储区域

  • 该区域有自己的名称(变量名)和类型(数据类型)
    • (名字用来寻找,类型用来约束存放的内容)
  • 该区域的数据可以在同一类型范围内不断变化

用来不断的存放同一类型的常量,并可以重复使用

注意:
变量的作用范围(一对{}之间有效,作用域,超出作用域之后,变量在内存中会被释放)

  • {} 局部代码块,可以定义局部变量的生命周期。
    初始化值

定义变量的格式:
数据类型 变量名 = 初始化值;
(格式固定)

Java强类型 –> 每种数据都定义了明确的数据类型,

每种数据类型在内存中分配的内存空间大小不相同

基本数据类型 –> 数值型 :–> 整数 byte,short, int ,long
–> 浮点数 float, double
字符型 char
布尔型 boolean

引用数据类型

  • 类class
  • 接口interface
  • 数组[]

注:整数默认为:int ,小数默认为:double

String 不是基本数据类型,是Java库的预定义类,任何Java类,都为引用类型

数据类型的设置,应该以需要赋值的类型来判定

类型转换:

自动类型转换
强制类型转换(显示类型转换)
什么时候使用强制类型转换???
如:(int)(a + b)强制转换为int

运算符

  • 只要是运算符,计算之后都会有结果

算数运算符

1
2
/ : Java中两个整数相除,商为整数,5 / 9 == 0
所以,要想得到小数,--> 5.0 / 9

赋值运算符

比较运算符

结果true;false

逻辑运算符(关系运算符)

逻辑运算符,用于连接两个boolean类型的表达式

  • & (单)与运算:两边都参与运算
  • | (单)或运算:同上
  • ! 非
  • ^ 异或
  • && (短路)与运算:当前面一个运算不满足时,后面的不需要运算
  • || (短路)或运算:同上

位运算符:

用于二进制位运算
(算法运算时用)
^ 异或运算时,

  • 一个数异或同一个数两次,结果还是这个数
  • (异或的小应用:对一个数据异或一次,相当于加密,在异或一次相同于解密(USBKey))

移位运算符

三元运算符

A?B:C
与下面代码效果相同

1
2
3
4
5
if (A){
B
}else{
C
}
  • 只要是运算符,计算之后都会有结果

位运算

  1. 最有效的方法计算2*8

    • 凡是涉及到2进制运算,位运算是最高效的方式
      2<<3 == 2*8 =16
  2. 对两个整数变量的值进行互换(不用第三方变量)

    1
    2
    3
    a = a ^ b;
    b = a ^ b;
    a = a ^ b; 计算的结果a、b实现互换

    这里的利用^ 的规律,一个数^同一个数两次,值不变

if条件判断

switch语句

格式

1
2
3
4
5
6
7
8
9
10
11
12
switch(表达式){
case 取值1:
执行语句;
break;
case 取值2:
执行语句2;
break;
...
default:
执行语句n;
break;
}

注:靠近结尾大括号的语句的break可以省略;

多个选项对应一个内容:

1
2
3
4
5
6
7
switch(month){
case 3:
case 4:
case 5:
System.out.println(month + "...");
break;
}

(switch语句不常用)

for 循环

1
2
3
for(初始化表达式; 循环条件表达式; 循环后的操作表达式){
执行语句; (注意: 循环体)
}

多个表达式之间用 , 逗号隔开

1
for(;;){}	 //无限循环

循环通常需要变量的变化来控制

for与while的特点:

  1. for和while可以互换;
  2. 区别
    • 如果需要通过变量来对循环控制,且该变量只作为循环增量(变量)存在时,用for更好,循环结束后,这个变量就被回收了。

当对一个条件进行一次判断时,可以使用if语句;
当对一个条件进行多次判断时,可以使用while语句;

注意:

  1. 在使用循环时,一定要明确哪些语句需要参与循环,哪些不需要;
  2. 循环通常情况下,需要定义条件,需要控制次数;

HashMap

存储结构

  • 简单的说,HashMap的存储结构是由数组和链表共同完成的。

数组:

  1. 在内存中的地址是连续的,大小固定,一旦分配,不能被其他引用占用
  2. 查询快,时间复杂度是O(1), 插入和删除的操作比较慢,时间复杂度是O(n),

链表:

  1. 存储方式是非连续的,大小不固定,特点与数组相反,
  2. 插入和删除快,查询慢。

HashMap是一种折中方案

  • HashMap, Y轴方向是数组,X轴方向是链表,的存储方式

HashMap基本原理:

2、根据Hash值,要找到对应的数组,所以对Entry[]的长度length求余,得到的就是Entry数组的index
3、找到对应的数组,就找到了所在的链表,然后按照链表的操作对Value进行插入、删除和查询操作

h%length求余,一般什么情况下利用该算法?

  • 典型应用:分组

HashCode

用最简单的方法来说,hashcode就是一个签名。当两个对象的hashcode一样时,两个对象就有可能一样。如果不一样的话两个对象就肯定不一样。
一般用hashcode来进行比较两个东西是不是一样的,可以很容易的排除许多不一样的东西。
最常用的地方就是在一堆东西里找一个东西。先用你要找的东西的hashcode和所有东西的hashcode比较,如果不一样的话就肯定不是你要找的东西。如果一样的话就很可能是你要找的东西。然后再进行仔细的比较两个东西是不是真的一模一样。

两个不同的东西的hashcode可以是一样的,不过这样会减慢运行速度,所以尽量避免(也就是所谓的碰撞)。

  1. 一个对象的散列码,什么是散列码呢,简单的说就是通过哈希算法算出来的一大窜数字之类的东西,和内存有关.
    如果对象1和对象2相等,说明他们的散列码相等!反过来就不一样了!
  2. 另外hashcode可以减少equals比较的次数,提高运算效率。

网上,
hashcode 常常和 equal 一起提到

Java

垃圾回收器只释放那些经由new分配的内存

只有当垃圾回收发生时,才会释放那些不用的内存空间,当时垃圾回收不一定什么时候发生

Java中的垃圾回收与C++的析构函数的不同:

  • 垃圾回收不一定会发生,所以在程序执行过程中,对象不一定会被回收,
  • 析构一定会发生,

垃圾回收只与内存有关,

  • 使用垃圾回收器的唯一原因是为了回收程序不在使用的内存

Java 继承

继承,也是一种代码复用

关键字:extends,

可以得到基类中所有的成员变量(域)和方法

Java 初始化的顺序

  1. 在类的内部,变量定义的先后顺序决定了初始化的顺序。
  2. 即使变量定义散布于方法定义之间(这里是指变量没有放在一起定义,而是散布在方法定义的前后),他们仍旧会在任何方法(包括构造器)被调用之前得到初始化
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    package demoTest;

    public class InitSeq {

    public static void main(String[] args) {
    House h = new House();
    h.f(); // show that construction is done
    }
    }

    class Window {
    Window(int marker){
    System.out.println("Window(" + marker + ")");
    }
    }

    class House {
    Window w1 = new Window(1); // before constructor
    House() {
    //show that we're in the constructor
    System.out.println("House()");
    w3 = new Window(33); // reinitialize the w3
    }
    Window w2 = new Window(2); // after the constructor
    void f() {
    System.out.println("f()");
    }
    Window w3 = new Window(3); // at end
    }
    在上面的代码中,House中,故意把几个Window对象的定义散布在各处,以证明他们会在构造函数及其他函数调用之前得到初始化

static的对象,会优先于非static对象初始化

  • 即先静态,后非静态

构造器可以看做是static方法

非静态实例初始化

  • java 中有一种称为“实例初始化”,用来初始化每一个对象的非静态变量

数组初始化:

  • java 中可以将一个数组赋值给另一个数组,即:
    1
    a2 = a1; (int[] a2; int[] a1 = {1,2,3,4})
    这中间真正做的是复制了一个引用,即a2和a1其实都是相同数组([1,2,3,4])的别名,即对a2的修改其实就是对相同数组的修改,a1也能看到修改后的内容;

在编写程序时,并不能确定在数组中需要多少个元素,该怎么办?

可变参数:
有可变参数的好处是,
就不用再显示地编写数组语法了
String[] args
String… args 可变参数仍旧可以是一个数组, 可以用于“具有可选的尾随参数”时

Integer是int的包装类型
自动包装机制可以将int提升为Integer

Java的 if…else 与switch 结构总结

swtich 从字节码上看是优于 if,
但是从测试结果来看在分支很多的情况下能显示出优势,一般情况下还是打不过 if

额外知识点:

现代 CPU 都支持分支预测 (branch prediction) 和指令流水线 (instruction pipeline),这两个结合可以极大提高 CPU 效率。对于像简单的 if 跳转,CPU 是可以比较好地做分支预测的。但是对于 switch 跳转,CPU 则没有太多的办法。 switch 本质上是根​据索引,从地址数组里取地址再跳转。

if 是跳转指令,如果是简单的跳转指令的话 CPU 可以利用分支预测来预执行指令,而 switch 是要先根据值去一个类似数组结构找到对应的地址,然后再进行跳转,这样的话 CPU 预测就帮不上忙了。

  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2022-2023 ligongzhao
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信