首页 > 技术文章 > Java基础知识

panlei3707 2019-01-16 10:21 原文

目录                                                               

1、数据类型

2、修饰符总结

  初始化块

3、String总结

4、Java集合(包括数组的知识)

5、File类

  5.1 File类创建和删除功能

  5.2 File类的判断功能

  5.3 File类的获取功能和修改名字功能

  5.4 File类的其它获取功能

6、IO流

  6.1 IO流分类

  6.2  OutputStreamWriter与InputStreamReader

  6.3 打印流

  6.4 对象操作流

7、多线程

  7.1 同步问题

  7.2 线程的生命周期

8、枚举&注解

  8.1 枚举

9、反射 

底部

 

  

 

 

1、数据类型

Java所有关键字都是小写的,TRUE、FALSE和NULL都不是Java关键字。

Java语言支持的类型分为两类:基本类型和引用类型。基本类型包括boolean类型和数值类型。引用类型包括类、接口和数组类型,还有一种特殊的null类型。

字符串不是基本数据类型,字符串是一个类,也就是一个引用数据类型。

如果使用一个巨大的整数值(超过了int类型的表数范围)时,Java不会自动把这个整数当作long类型来处理。如果希望系统将一个整数值当成long类型来处理,应该在这个整数值后增加 l 或者 L 作为后缀。推荐使用  L

Java语言的浮点类型默认是 double类型,如果希望Java将一个浮点类型值当成 float 类型来处理,应该在这个整数值后增加 f 或者 F 作为后缀。

 ----练习:Java生成随机数 

import java.util.Random;
public class myRandom {
public static void main(String[] args) {
Random r = new Random();
// 获取数据范围 [0,10)
int n = r.nextInt(10);
System.out.println(n);
}
}

 

2、修饰符总结
定义类的修饰符:public、final、abstract

定义成员变量的修饰符:public、protected、private、static、final(其中public、protected、private三个最多出现其中一个,可以与static、final组合起来修饰成员变量)
定义方法的修饰符:public、protected、private、static、final、abstract(其中public、protected、private三个最多出现其中一个;final和abstract最多出现其中一个它们可以与static组合起来修饰方法)
定义构造方法的修饰符:public、protected、private三个其中一个

 



final关键字:
  final修饰的类不能被继承,修饰的方法不能被重写,修饰的变量不可以修改成为常量

static关键字:
  它的作用是用于区分成员变量、方法、内部类、初始化块这四种成员到底属于类本身还是属于实例。
  静态的加载优于对象,随着类的加载而加载。所以静态成员不能直接访问非静态成员。static修饰的方法中无法使用this关键字

初始化块
格式: 修饰符只能是 static,使用static修饰的初始化块被称为静态初始化块
  [修饰符] {
   ...
  }

普通初始化块:当创建对象时,系统总是先调用该类里定义的初始化块,然后调用相应的构造器。
当Java创建一个对象时,系统先为该对象的所有实例变量分配内存,接着程序开始对这些实例变量执行初始化,其初始化的顺序是:先执行初始化块或声明实例变量时指定的初始值(按照在代码中的顺序执行),再执行构造器里指定的初始值。

 创建一个java对象时,不久会执行该类的普通初始化块和构造器,而且系统会一直上溯到java.lang.Object类,先执行java.lang.Object类的初始化块,开始执行java.lang.Object的构造器,依次向下执行其父类的初始化块,开始执行其父类的构造器......最后才执行该类的初始化块和构造器,返回该类的对象。


静态初始化块:
负责对类进行初始化

运行结果:静态只初始化一次,先上溯

 

3、String总结

==的作用:比较基本数据类型的值是否相同,比较引用数据类型的地址是否相同

 

用"+"拼接字符串内存示意图

 用"+"做字符串拼接的时候,是将拼接后的字符串新生成一个,原先的会被废弃掉,造成巨大的内存浪费。

StringBuilder了解一下


4、Java集合(包括数组的知识)

需要集中存放多个数据,但数组长度不可变化,且无法保存具有映射关系的数据
常用的集合有哪些? List Set Map
4.1 List

存储的元素有索引,可以重复

4.2 Set


存储的元素无索引,不可以重复,无序状态

4.3 Map

存储键-值对形式的数据,键值不可重复
Map的遍历方法:
利用Map的:方法
 Set<Map.Entry<K,V>> entrySet()
          返回此映射中包含的映射关系的 Set 视图。
然后遍历这个Set集合对象即可,获取到每一个Map.Entry<K,Y>元素,然后调用其

 





并发修改异常 java.util.ConcurrentModificationException
产生原因:在遍历集合的同时对其进行修改
解决办法:不在遍历集合的同时对其进行修改
示例代码:遍历students这个ArrayList集合,并在符合条件时删除其中的元素
for(Student s:students){
if(s.getId().equals(id)){
students.remove(s);
flag = true;
}
}
修改后:用一个下标记录要删除的元素位置
for(Student s:students){
if(s.getId().equals(id)){
index = students.indexOf(s);
flag = true;
}
}

迭代器知识
public interface Iterator<E> :对 collection 进行迭代的迭代器。在对集合进行迭代时,要将其转换为一个迭代器对象进行操作。
Collection中有:可以获得迭代器对象
 Iterator<E> iterator()
          返回在此 collection 的元素上进行迭代的迭代器。
具体到特定的类型,例如List中有:获得迭代器对象
 ListIterator<E> listIterator()
          返回此列表元素的列表迭代器(按适当顺序)。
ListIterator中有add方法,可以实现迭代期间修改列表,从而不引发  并发修改异常   

 

5、File类
文件和目录路径名的抽象表示形式。File类的实例是不可变的;也就是说,一旦创建,File对象表示的抽象路径名将永不改变。
通过指定路径创建File对象时,并不会去检查路径是否存在或者文件是否存在

5.1 File类创建和删除功能

boolean createNewFile():指定路径不存在该文件时时创建文件,返回true;存在时不创建,并返回false

boolean mkdir():当指定的单级文件夹不存在时创建文件夹并返回true,否则返回false 

boolean mkdirs():当指定的多级文件夹某一级文件夹不存在时,创建多级文件夹并返回true,否则返回false

boolean delete():删除文件或者删除单级文件夹      存在时删除并返回true,不存在时返回false     不能删除拥有子文件或者子文件夹的文件夹

 

5.2 File类的判断功能

boolean exists():判断指定路径的文件或文件夹是否存在

boolean isAbsolute():判断当前路路径是否是绝对路径

boolean isDirectory():判断当前的目录是否存在

boolean isFile():判断当前路径是否是一个文件

boolean isHidden():判断当前路径是否是隐藏文件

 

5.3 File类的获取功能和修改名字功能

 File getAbsoluteFile():获取文件的绝对路径,返回File对象

 String getAbsolutePath():获取文件的绝对路径,返回路径的字符串

 String getParent():获取当前路径的父级路径,以字符串形式返回该父级路径

 File getParentFile():获取当前路径的父级路径,以字File对象形式返回该父级路径

 String getName():获取文件或文件夹的名称

 String getPath():获取File对象中封装的路径,绝对就返回绝对,相对就返回相对

 long lastModified():以毫秒值返回最后修改时间

 long length():返回文件的字节数

 boolean renameTo(File dest): 将当前File对象所指向的路径 修改为 指定File所指向的路径,修改的文件不能存在,也就是不能重名

 

5.4 File类的其它获取功能

String[] list():以字符串数组的形式返回当前路径下(必须是文件夹路径)所有的文件和文件夹的名称

File[] listFiles():以File对象的形式返回当前路径下所有的文件和文件夹的名称

static File[] listRoots():获取计算机中所有的盘符

 

 

6、IO流

 

6.1 IO流分类:

  按流向分类:

    输入流:    读取数据  FileReader  Reader

    输出流:    写出数据  FileWriter   Writer

  按数据类型分类:

    字节流:(一次读取一个字节,不能因为有字符流就不需要字节流,因为图片、视频之类的数据底层还是字节流形式)

      字节输入流:    InputStream

      字节输出流:    OutputStream

    字符流:(为了方便一次读取多个字节,比如中文

      字符输入流:    Reader

      字符输出流:    Writer

 

二进制文件(图片、视频、音频等)只能使用字节流

 

6.2 OutputStreamWriter与InputStreamReader

一个案例:利用字符流读取一个文件中的数据在命令行中展示

首先介绍标准的输入输出流:System.in     System.out

查看System的文档

  Static InputStream in

  Static PrintStream out

可以看出标准的输入输出流是字节流

示例代码:

 

import java.io.*;

public class MyIO {
    public static void main(String[] args) {
        BufferedReader br = null;
        OutputStream os = null;
        try {
            // 创建输入流对象
            br = new BufferedReader(new FileReader("test.txt"));
            // 创建输出流对象
            os = System.out;

            String line;
            while ((line=br.readLine()) != null) {
                os.write(line.getBytes());
                os.write("\r\n".getBytes());
            }


        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //释放资源
            try {
                os.close();
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

 

从代码处可以看出,标准输出在输出数据时,由于我们获取的数据是字符流获取的,而输出只能是以字节的形式,需要我们将数据转换为字节数组,这样很不方便,那我们需要考虑Java是否提供了一种将字节流转换的工具,使其可以处理字符流,而不是让我们自己手动转换。

这种解决方法就是OutputStreamWriter与InputStreamReader  这两个转换流

 

利用这个类我们对代码进行修改


import java.io.*;

public class MyIO {
public static void main(String[] args) {
BufferedReader br = null;
BufferedWriter bw = null;
try {
// 创建输入流对象
br = new BufferedReader(new FileReader("test.txt"));
// 创建输出流对象
bw = new BufferedWriter(new OutputStreamWriter(System.out));

String line;
while ((line=br.readLine()) != null) {
bw.write(line);
bw.newLine();
}


} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//释放资源
try {
bw.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
 

 

为了更加方便操作,我们直接将OutputStreamWriter再封装一层,成为BufferedWriter,这里我们就不需要自己再进行字符串转换为字节数组的操作了。

同理也可以对标准输入流转换

 

 6.3 打印流

PrintStream   与   PrintWriter

PrintWriter是一个包装流,字符打印流。

具有写出数据自动刷新(需要在构造方法中设置,并使用特有方法),自动换行(使用println()方法)的特有功能,具体参考API

 

6.4 对象操作流

 详情见Java面向对象 的对象操作流部分

 

7、多线程

你吃饭吃到一半,电话来了,你一直到吃完了以后才去接,这就说明你不支持并发也不支持并行。
你吃饭吃到一半,电话来了,你停了下来接了电话,接完后继续吃饭,这说明你支持并发。
你吃饭吃到一半,电话来了,你一边打电话一边吃饭,这说明你支持并行。

并发的关键是你有处理多个任务的能力,不一定要同时。
并行的关键是你有同时处理多个任务的能力。

所以我认为它们最关键的点就是:是否是『同时』。

如果某个系统支持两个或者多个动作(Action)同时存在,那么这个系统就是一个并发系统。如果某个系统支持两个或者多个动作同时执行,那么这个系统就是一个并行系统。并发系统与并行系统这两个定义之间的关键差异在于“存在”这个词。

在并发程序中可以同时拥有两个或者多个线程。这意味着,如果程序在单核处理器上运行,那么这两个线程将交替地换入或者换出内存。这些线程是同时“存在”的——每个线程都处于执行过程中的某个状态。如果程序能够并行执行,那么就一定是运行在多核处理器上。此时,程序中的每个线程都将分配到一个独立的处理器核上,因此可以同时运行。

我相信你已经能够得出结论——“并行”概念是“并发”概念的一个子集。也就是说,你可以编写一个拥有多个线程或者进程的并发程序,但如果没有多核处理器来执行这个程序,那么就不能以并行方式来运行代码。因此,凡是在求解单个问题时涉及多个执行流程的编程模式或者执行行为,都属于并发编程的范畴。

摘自:《并发的艺术》 — 〔美〕布雷谢斯
实现多线程的方法1:继承Thread类
public class MyThread {
    public static void main(String[] args) {
        Thread1 t1 = new Thread1();
        Thread2 t2 = new Thread2();
        t1.setName("one");
        t2.setName("two");
        t1.start();
        t2.start();
    }
}

-----------------------------------
public class Thread1 extends Thread {
    @Override
    public void run() {
        for(int i=0; i<100; i++) {
            System.out.println(super.getName() + ":" + i);
        }
    }
}
-----------------------------------
public class Thread2 extends Thread{
    @Override
    public void run() {
        for(int i=0; i<100; i++) {
            System.out.println(super.getName() + ":" + i);
        }
    }
}

 实现多线程的方法2:实现Runable接口

public class MyRunable {
    public static void main(String[] args) {
        Runable1 r1 = new Runable1();
        Thread t1 = new Thread(r1);
        t1.start();

        Thread t2 = new Thread(r1);
        t2.start();
    }
}
-------------------------------------------
public class Runable1 implements Runnable {
    @Override
    public void run() {
        for(int i=0; i<100; i++){
            System.out.println(Thread.currentThread().getName() + ":" + i);
        }
    }
}

 

为什么会有继承Thread类实现多线程和实现Runable实现多线程两种方法呢?

主要是因为Java的单一继承,如果我们继承了Thread类后还想继承其他类,显然是做不到的,但实现Runable接口便还可以继承其他类,所以推荐使用第二种方法

 

7.1 同步问题:synchronized()

涉及到多线程必然会涉及到同步问题,也就是对于共享资源,同一时刻只能有一个线程进行访问。

synchronized可以用来修饰代码块和方法

非静态方法的锁对象是this,静态方法的锁对象是当前类的字节码对象

 

 

7.2 线程的生命周期

 

 

 

8、枚举&注解

8.1 枚举

自定义枚举类

class Season{
private final String seasonName;
private final String seasonDesc;

private Season(String seasonName, String seasonDesc){
this.seasonName = seasonName;
this.seasonDesc =seasonDesc;
}

public static Season SPRING = new Season("Spring", "春天");
public static Season SUMMER = new Season("Summer", "夏天");
public static Season AUTUMN = new Season("Autumn", "秋天");
public static Season WINTER = new Season("Winter", "冬天");

public String getSeasonName() {
return seasonName;
}

public String getSeasonDesc() {
return seasonDesc;
}

@Override
public String toString() {
return "Season{" +
"seasonName='" + seasonName + '\'' +
", seasonDesc='" + seasonDesc + '\'' +
'}';
}
}

利用关键字:enum

public enum Season {
SPRING("spring","春天"),
SUMMER("summer","夏天"),
AUTUMN("autumn","秋天"),
WINTER("winter","冬天");

private final String seasonName;
private final String seasonDesc;
private Season(String seasonName, String seasonDesc){
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}

public String getSeasonName() {
return seasonName;
}

public String getSeasonDesc() {
return seasonDesc;
}

@Override
public String toString() {
return "Season{" +
"seasonName='" + seasonName + '\'' +
", seasonDesc='" + seasonDesc + '\'' +
'}';
}
}

 

9、反射

java.lang.Class是反射的源头,我们创建了一个类,通过编译(java.exe),生成对应的.class文件、之后我们使用java.exe加载(JVM的类加载器)此.class文件,此.class文件加载到内存以后,就是一个运行时类,存放在缓存区,这个类本身就是一个Class的实例

具体内容见:Java反射






推荐阅读