Javase
前言
以前都是记笔记,每篇文章都很短而且很乱,现在学完很久了,有些东西都快忘了,最近又刚刚整完主题,所以索性就整理一下前面的文章,顺便整合起来复习一下。
这是我学习JavaSE的时候记的笔记,文章较长,建议目录直接跳转
什么是JavaSE
复习前先来看看什么是JavaSE,来看看百度百科是怎么描述的。(大概了解一下就好了)
Java SE(Java Standard Edition,Java 标准版)是Java技术的核心和基础,是Java ME和Java EE编程的基础 [1] 。Java SE是由Sun Microsystems公司于1995年5月推出的Java程序设计语言和Java平台的总称。
Java环境配置
学习Java的第一件事情就是要先配置好Java所需要的环境,不然运行不了还怎么学习。
下载JDK
JDK是Java语言的软件开发工具包,是整个Java开发的核心,它包含了Java的运行环境和Java工具,所以这个是必须要下载的。
下载的版本就选Java8好了,不一定最新的就是最好的,当然最新的也可以。至于IDE嘛,喜欢哪个用哪个,我用的就是idea
设置环境变量
此电脑,右键,点击“属性”,点击“高级系统设置”,点击“高级”下的环境变量,配置下面三个变量,有就添加变量,没有就新建变量
分别配置好以下三个环境变量
JAVA_HOME
路径就填JDK的安装路径PATH
路径填JDK命令文件的位置,即bin目录的位置CLASSPATH
开头输入“.;”,然后填lib目录的位置
检查是否配置成功
配置完了之后就去检查一下有没有配置成功吧,以免之后出错。去cmd输入命令java-version,若有版本号出现就证明配置成功了。
省略一部分
时间不允许我写这么多了,所以我就跳过了一些基本知识,之后我在补(如果有机会的话)。
- 操作符
- 变量和常量
- 控制流程语句(for,if,while)
这些是跟很多编程语言都是一样的,特别是和C,C++,所以我省了
方法
方法也就是C语言里面的函数,也就是一段实现特定效果的语段。main方法就是主方法,程序的入口。
方法的简单使用
1 | public class Hello { |
方法重载
方法重载就在于方法名是一样的,参数列表不一样。
重载不是重写,这是两个概念,不要弄混了
1 | public class Hello { |
方法递归
递归的思想就是自己调用自己(套娃),比如下面这个求阶乘的方法。
1 | public class Hello { |
面向对象
成天都说Java是面向对象的语言。那什么是面向对象编程呢?
面向对象是相对于面向过程来讲的,面向对象方法,把相关的数据和方法组织为一个整体来看待,从更高的层次来进行系统建模,更贴近事物的自然运行模式
大概了解一下就好了,Java是离不开类和对象的,所以之后就会感受到什么是面向对象编程。
类和对象
类就是一个抽象的概念,对象就是从类里实例化出来的个体。之后的Java学习都要用到。现在就来定义一个简单的类。
1 | //注意一个类文件里面只能有一个public类 |
类属性和类方法
上述的i和print()就本别是类属性和类方法。把类当作是一个整体,类属性就相当于是一个部件,类方法相当于部件实现的功能。
类属性和方法调用必须通过对象,比如demo类有个test对象,那就是test.i和test.print()
访问修饰符
上述类,属性,对象都用public来修饰,public就是一个访问修饰符,访问修饰符是来设定权限的,设定谁才能使用这个类,以下是四种Java的访问权限。
访问级别 | 访问修饰符 | 同类 | 同包不同类(不含子类) | 同包子类 | 不同的包(不含子类) | 不同包子类 |
---|---|---|---|---|---|---|
公开的 | public | √ | √ | √ | √ | √ |
受保护的 | protected | √ | √ | √ | √ | |
默认的 | 什么都不加 | √ | √ | |||
私有 | private | √ |
引用
如果一个变量的类型是 类类型,而非基本类型,那么该变量又叫做引用。
听起来很绕,写起来就知道什么意思了。
使用类就要创建这个类的对象。就比如new demo()。但也只是创建对象,无法访问到它,所以就用引用来代表这个对象。
1 | //引用了d这个变量来代表新创建的demo对象 |
构造方法
类还有一个很重要的概念就是构造方法,也叫构造器。构造方法使用来创建类的,所以方法名与类名一模一样,没有返回值,如果要实例化对象,就一定会用到构造方法。
1 | public class Hello { |
需要注意的是,系统会默认提供无参的构造方法,所以你能使用new demo()来创建对象,但如果定义了有参的构造方法,无参的就会没了,所以就不能使用new demo()来创建对象,所以养成个好习惯,创建类的时候,顺便写上无参的构造方法。
Java的三大特性
继承
关键字extends
子类继承父类的所有方法和属性,Java的继承包括两种:
- 类的单继承,即只能继承一个父类
- 接口的多继承,一个类可以实现(继承)多个接口
封装
关键字就是private,protected,public
封装就是将一个类里的属性和方法包装起来,严格控制访问权限。就比如JavaBean就是一个标准的封装
1 | class demo{ |
多态
多态就是同一个行为具有多个不同表现形式或形态的能力。实现多态的三个必要条件有
- 继承
- 重写
- 父类引用指向子类对象
可以先看个简单的例子
1 | public class Test { |
this与super关键字
this
this的本质是”创建好的对象的地址“,经常用为当前对象。下面举个例子来说明this的使用方法。
1 | // 1 |
使用this关键字来调用重载的构造方法时,可以避免相同的初始化代码,但只能在构造方法中使用,而且须位于构造方法的第一句。
this不能用于static方法中。因为static方法是属于类的,this是代表对象,具体详情可以参考下面关于static的描述
super
super可以理解为指向父类对象(离得最近的)的一个指针,使用方法也有三种。
1 | public class demo { |
两者对比
- 子类的构造函数中要调用super(),一定要放在首行,即使不用系统也会自行调用super(),即子类调用自己的构造器时会先调用父类的,先创建一个父类的对象
- super是从子类中调用父类的方法或变量,而this为在同一类中调用其它方法或变量
- 从本质上来讲this是一个指向本对象的指针,而super是一个Java的关键字
数组
数组是一个固定长度的,包含了相同类型数据的容器。
一维数组
数组的声明
1 | // 优先使用这种方法声明 |
数组的实例
1 | // 优先使用这种方法实例 |
创建数组
1 | //dataType[] arr_name = new dataType[arraysize]; |
三种初始化方式
1 | // 1.静态初始化 |
二维数组
二维数组可以理解为一个数组,这个数组存着几个一维数组,所以Java的数组可以是不规则的。
二维数组创建:
1 | type[][] arr_name= new type[int][int]; |
二维数组的初始化
1 | //1.静态初始化 |
接口
接口时一个抽象的类型,跟抽象类有着差不多作用,但又不是类,相当于一个模板需要我们去完善,实现功能,所以接口是不能被实例化的,使用它就需要继承它来实现。
抽象类
抽象类是一种特殊的类,它的作用就是给子类提供了模板,它不能被实例化,所以抽象类是被当作父类去继承的。说到抽象类,就先聊聊什么是抽象类。类里有抽象方法的类被叫为抽象类,但要注意抽象类不是一定有抽象方法。
定义抽象类就用关键字abstract,将类声明为抽象类
抽象方法
有抽象方法的类被叫为抽象类,那什么是抽象方法呢,就是专门给我们去继承实现的方法。所以抽象方法是必须要被重写的,而且继承了该抽象类就必须重写抽象方法,不然系统会编译出错。
抽象方法的定义也是用关键字abstract,抽象方法是必须被重写的,所以它是不需要方法体的。
子类继承了抽象类,没重写其抽象方法子类就必须在声明为抽象类,还有的就是构造方法和用static修饰的类方法是不能被声明为抽象方法的。
接口
大致了解了抽象类和抽象方法就能理解接口是什么了吧。接口时抽象方法的集合,虽然也可以定义变量,但最好不要破坏了接口的特性,全是抽象方法就好了。
接口是用关键字interface来定义的,类通过关键字implements去实现接口,而且里面的方法是不能有抽象方法的,继承的类必须重写里面所有的抽象方法。
这是一个简单的例子
1 | public class demo implements demotest { |
接口的多继承
在知道了接口之后,就会有个疑问,既然有了抽象类的概念,为什么还要特意设计接口呢?这就要涉及到接口的一个特点了。
类是只支持单继承,而接口支持多继承。
人们在写程序的时候发现,在继承了一个类之后,人们就不能继续继承了,有些功能又要重新定义和实现,因为Java不想我们弄得很乱,不能像C++那样可以支持继承多个类,所以设计了接口来解决这种问题。可以通过下面的列子来大概了解接口的魅力。
1 | //继承了demoA的方法,又继承了demoB的方法,如果还想添加功能可以再写接口在实现 |
接口的每个方法都会被隐式的指定public abstract来修饰,变量会被隐式的指定 public static final修饰。
JDK8之后,接口也可以有方法体和静态方法了,但怎么说呢,在我看来还是不加的好
Scanner类
1 | import java.util.Scanner |
System.in和System.out
- 该方法只能从键盘获取一个字符,而且获取的是char类型的,其他类型的难处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import java.io.IOException;
public class Main {
public static void main(String[] args) {
System.out.println("请输入一个字符:");
char c = 0;
try {
c = (char) System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(c);
}
}
InputStreamReader和BufferedReader
- 可以获取字符串,但是获得int,float等类型需要转换
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) {
System.out.println("请输入:");
InputStreamReader is = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(is);
try {
String msg =br.readLine();
System.out.println(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
String类
在Java中,有个很重要的类-String类,注意S是大写,就是我们所说的字符串类,这使得我们使用字符串十分方便。
String的简单应用
1 | public class demo { |
注意String创建了就是不可改变的。
既然字符串是不可变的,那为什么会出现下面的操作呢?
1 | public class demo { |
有人会好奇str1为什么还能继续赋值呢。其实说字符串不可变,是说字符串本身不可变,即“hello”等字符串不能改变,str1只是一个引用,继续赋值只是换了一个地址索引,原来的“hello”还是会存在内存中。
类里经常使用的方法
都是经常使用的一些方法
1 | //返回 char指定索引处的值 |
异常
异常是导致程序中断的事件,它不是算是错误,错误error是值jvm运行你的Java程序出的问题。
Exception类是所有异常类的父类
RuntimeException(运行时异常)
- ArithmeticException 试图除以0异常
- NullpointerException 空指针异常
- ClassCastException 强制转换异常(引用数据类型转换)
- ArraylndexOutOfBoundsException 数组索引越界异常
- NumberFormatException 数字格式化异常
CheckedException(已检查异常)
这类异常在编译时必须处理,否则无法通过编译
处理异常的方法
用try-catch-finally来捕获异常
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class demo {
public static void main(String[] args) {
try //try来捕获异常
{
System.out.println("try");
throw new Exception( );
}
catch(Exception e) //catch来处理异常
{
System.err.println("catch");
e.printStackTrace( );
}
finally //finally是必须执行的语句
{
System.out.println("finally");
}
}
}throws抛出异常让系统解决
1
2
3
4
5public class demo {
public static void main(String[] args) throws Exception {
}
}
泛型
泛型即参数化类型,本质为数据类型的参数化 ,也就是说所操作的数据类型被指定为一个参数的方式传递,类似于方法中的变量参数。可以用在类、接口、方法的创建中,分别简称为泛型类、泛型接口、泛型方法。
为什么要使用泛型呢?
首先举一个简单的例子
1 | public class Test { |
nbsp;运行后就会发现程序崩溃了,这是因为在ArrayList中加入了Integer和String类型的数据,转换就出现了异常,所以为了解决一些集合内的类型转换的问题,就出现了泛型,泛型的使用可以减少类型转换和转换异常的情况。
泛型的特性
- 泛型只在编译阶段有效,编译后程序会采取去泛型化的措施,泛型是不会进入到运行阶段的
- 泛型类型在逻辑上可以看成是不同的类型,实际上都是相同的基本类型
使用方法
泛型有三种使用方式,泛型类,泛型接口,泛型方法。
集合框架
Collection
首先学容器之前还是学习一下Collection接口,毕竟List与Set接口都是继承的Collection的,所以List与Set都有它的方法,别与Collections类弄混了,前者是集合类的上层接口,后者是一个集合框架的帮助类
1 | // 先新建两个Collection |
List
概念
List是有序,可重复的容器,List接口继承了Collection,因为是有序的,所以List是有索引位置的,因此相对与Collection接口,会有一些 特殊的关于索引位置的方法
常用实现类
LinkedList
LinkedList底层用双向链表实现的储存。查询效率低,删减效率高,线程不安全
ArrayList
ArrayList底层是用数组实现的储存。查询效率高,增删效率低,线程不安全
Vector
Vector底层是用数组实现的List,相关的方法都加了同步检查,故线程安全,效率低
当需要线程安全时就用Vector实现类。查找多就用ArrayList实现类,增删多就用LinkList。
特殊方法
1 | List<String> list = new ArrayList<>(); |
一些要点
- List允许加重复的元素
- List允许存在null元素
- List是有索引位置的
- List是支持泛型的,所以尽量使用List时要加泛型
Map
概念
Map是存储Key与Value的容器,每个key都会对应一个Value值,所以键对象不能重复,如果存放相同的键对象,对应值对象会被新的值对象代替。
常用实现类
- HashMap
底层是通过哈希表来实现的。线程不安全,但效率高。允许Key与Value为null。
HashTable
底层实现与HashMap几乎一样,只是方法添加了synchronized来确保线程同步检查。所以线程安全,但效率低,且不允许Key与Value为null。
TreeMap
底层是通过红黑二叉树来实现的。HashMap效率高于TreeMap,需要排序时才会选择使用TreeMap,即按照Key递增的顺序排序,如果是类排序可以考虑使用comparable接口来实现
常用的方法
1 | Map<Integer,String> map1 = new HashMap<>(); |
Set
概念
Set是无序而且是不可重复的,与List一样继承Collection接口。即没有索引只能遍历查找,通过equals方法为true的不能放入,即使是NULL也只能有一个。往Set里面加入元素,本质就是把这个元素作为Key加入到内部的Map里,由于Map里的key是不重复的所以Set也不重复
常用实现类
HashSet
底层是采用HashMap实现的,本质是简化版的HashMap,因此查询与增删效率较高。
TreeSet
常用方法
因为Set继承与Collection接口,而且没有新增方法,所以方法与Collection是一样的。
迭代器
概念
迭代器是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。
使用
遍历List容器
1
2
3
4
5
6
7
8
9
10
11List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
//使用list里的iterator方法返回一个迭代器,使用该迭代器的hasNext方法得到下一个对象,进而遍历容器
for(Iterator<String> iter = list.iterator();iter.hasNext();){
String t = iter.next();
System.out.println(t);
}遍历Set容器
1
2
3
4
5
6
7
8
9
10
11//遍历Set的方法与遍历List是一样的
Set<String> set = new HashSet<>();
set.add("1");
set.add("2");
set.add("3");
set.add("4");
set.add("5");
for(Iterator<String> iter = set.iterator();iter.hasNext();){
String t = iter.next();
System.out.println(t);
}遍历Map容器
1
2
3
4
5
6
7
8
9
10Map<Integer,String> map = new HashMap<>();
map.put(1, "student1");
map.put(2, "student2");
map.put(3, "student3");
//通过Map.entrySet使用iterator遍历key和value
Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, String> entry = it.next();
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
容器遍历汇总
List遍历
1 | List<String> list = new ArrayList<>(); |
Set遍历
1 | //Set的遍历与List大同小异,只是没有用索引遍历 |
Map遍历
1 | //第一种,用增强for循环遍历 |
Collections工具类
概念
类java.util.Collections提供了对Set,List,Map的辅助方法
常用方法
1 | List<String> list = new ArrayList<>(); |
IO流
IO流的分类
- 根据处理数据的类型不同分为:字符流和字节流
- 根据数据流向的不同分为:输入流和输出流
节点流
文件字节流( 数据源为文件)
FileInputStream 通过字节的方式从文件到程序,读取文件
FileOutputStream 通过字节的方式从程序到文件,写入文件
文件字符流( 数据源为文件)
FileReader 通过字符的方式从文件到程序
FileWriter 通过字符的方式从程序到文件
处理的是字符数组 char
字节数组流(数据源为字节数组对象)
ByteArrayInputStream 通过字节的方式从字节数组到程序
ByteArrayOutputStream 拖过字节的方式从程序到字节数组
使用流之后需要释放流,字节数组流不需要释放,系统会自动释放的
在cry - with -resources 工具类里,在抛出异常的try{}后加入流的声明,则会帮你自动释放资源,比如try(is;os;is1;os2){}
处理流
字节缓冲流:
BufferedInputStream
BufferedOutputStream
默认是缓存8K,可以自己修改,原理类似于修饰模式。
可以提升性能,运输效率,只用关闭外层的流即可,内层会自动关。手动关闭的话要从里往外关闭
字符缓冲流:
BufferedReader
readLine() 读取一行文字
BufferedWriter
newLine() 换行符
不要用父类引用指向子类对象,不然用不了这些新增方法
转换流:
InputStreamReader
OutputStreamWriter
将字节流转为字符流,方便处理(字节流需全文本)
能为字节流指定字符集
数据流:
DataInputStream
DataOutputStream
保留数据类型,读取的顺序与写出保持一致
数据流里放的是InputStream与OutputStream的字节流
对象流:
ObjectInputStream 反序列化
ObjectOutputStream 序列化
先写出后读取,读取的顺序与写出的顺序保持一致
不是所有的对象都能序列化,必须是实现了Serializable接口
方法和数据流差不多,多了writeobject和readObject
如果不需要序列化某个对象的值,就用transient来修饰类的对象
打印流:
PrintfStream
PrintWriter
随机访问:
RandomAcessFile
两个模式(mode)
“r”读 “rw”读写
合并:
SequenceInputStream
先用Vector容器来储存输入流,然后用该容器的elements()方法返回SequenceInputStream的参数,从而合成一个流
TCP与UDP的简单实现
TCP
使用基于TCP协议的Socket网络编程
TCP协议基于请求- 响应模式
利用IO流实现数据的传输
TCP使用的基本流程
1 | import java.io.DataInputStream; |
1 | import java.io.DataOutputStream; |
UDP
基于UDP协议的Socket网络编程实现
不需要IO流实现数据传输,数据被打包成包裹发送到目的地(注意传输的包裹不要太大)
用到的两个类:
- DatagramPacket
- DatagramSocket
代码实现
1 | import java.net.DatagramPacket; |
1 | import java.net.DatagramPacket; |
多线程
笔记丢了,下次在补
终于整理完了,暂时不写了,如果想到有些漏的,在加上,还有一些其他的知识,我会用单独的文章来写
笔记有一些是网上的,所以要是有侵犯到你的权益可以通知我删除。