踩坑指南
- 主流版本 jdk8
- idea 要和maven版本对应,否则没法引入依赖
- mac 删除多个java
/Library/Java/JavaVirtualMachines
目录下删除多余版本的java(eg, 我装了最新版的jdk14,但最常用的是jdk8) - windows 删除服务 管理员运行cmd,
sc delete mysql80
安装配置maven
- 下载maven
- 添加M2_HOME到系统变量
- 添加到path
- mvn -h test
- 配置 settings.xml
//设置本地仓库地址
<localRepository>D:\mavenPackages</localRepository>
//设置maven镜像
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
</mirror>
安装配置tomcat
CATALINA_HOME=D:\ProgramFiles\apache-tomcat-9.0.10
%CATALINA_HOME%\lib
%CATALINA_HOME%\lib\servlet-api.jar
%CATALINA_HOME%\lib\jsp-api.jar
3.修改配置, tomcat目录下的conf/tomcat-users.xml
增加下边的几行到文件最后边
<role rolename="manager-gui"/>
<role rolename="admin-gui"/>
<user username="admin" password="admin" roles="admin-gui"/>
<user username="tomcat" password="admin" roles="manager-gui"/>
4.intellj中的tomcat运行时,除了要配置tomcat之外,还要配置deploy
5. tomcat log 乱码,修改 tomcat/conf 下的logging.proper,修改编码为系统默认的GBK即可
java.util.logging.ConsoleHandler.encoding = GBK
basic
保证Java语言跨平台。针对不同的操心系统提供不同的JVM
JRE java程序的运行环境。包括JVM和核心类库
JDK包含jre和开发工具
常量
final int SIZE = 1
类型转换
String is1 = "11";
// 字符串转数字
int int1 = Integer.parseInt(is1); // 11
// 数字转字符串
System.out.println(11 + "22");
System.out.println(String.valueOf(int1));
字符串
String str1 = "huahua";
// string的方法都是返回一个新字符串
String str2 = str1.replace("h", "1"); // 1ua1ua
String str3 = str2.replaceFirst("1", "p"); // pua1ua
String str4 = str3.toUpperCase(); // PUA1UA
String str5 = str4.toLowerCase(); // pua1ua
String str6 = str5.trim(); // 去掉首尾空格
boolean a = str1.contains("ua"); // 是否包含
char b = str1.charAt(0); //返回指定位置字符
//字符串分割
String[] temp = str1.split("2");
String StringBuffer StringBuilder
- 如果要操作少量的数据用 String;
- 多线程操作字符串缓冲区下操作大量数据 StringBuffer;
- 单线程操作字符串缓冲区下操作大量数据 StringBuilde
- java中字符串是不可变的
String s1 = "huahua";
String s2 = "huahua";
System.out.println(s1 == s2); // 引用相同
System.out.println(s1.equals(s2)); // 值相同
StringBuffer sf1 = new StringBuffer("huahua");
sf1.append("-lala");
sf1.insert(1, "oo");
System.out.println(sf1.toString());
数组
int[] arr = { 1, 2}; // 直接赋初值并定义数组的大小
int[] arr1 = new int[3]; // 用运算符new 分配内存再赋值, 里边的值默认是null
日期时间
// 日期操作
LocalDate date = LocalDate.now();
LocalDate date1 = LocalDate.of(2020, 6, 12);
System.out.println(date.getYear());
System.out.println(date.getMonthValue());
System.out.println(date.getDayOfMonth());
System.out.println(date.equals(date1));
System.out.println(date.isAfter(date1));
// 字符串得到日期
String dateText = "20180924";
LocalDate date2 = LocalDate.parse(dateText, DateTimeFormatter.BASIC_ISO_DATE);
System.out.println(date2);
// 时间操作
LocalTime time = LocalTime.now();
System.out.println("当前时间=" + time);
System.out.println(time.getHour());
System.out.println(time.getMinute());
System.out.println(time.getSecond());
面向对象
继承
- java中是单继承,一个子类只能有一个父类
- 继承中的构造方法 当生成子类对象时,Java默认首先调用父类的不带参数的构造方法,然后执行该构造方法,生成父类的对象。接下来,再去调用子类的构造方法,生成子类的对象
- 如果子类使用super()显式调用父类的某个构造方法,那么在执行的时候就会寻找与super()所对应的构造方法而不会再去寻找父类的不带参数的构造方法。与this一样,super也必须要作为构造方法的第一条执行语句,前面不能有其他可执行语句
- 当两个方法形成重写关系时,可以在子类方法中通过super.run()形式调用父类的run()方法
- 重写(覆盖):子类覆盖方法和父类被覆盖方法的方法返回类型,方法名称,参数列表必须相同,子类覆盖方法的访问权限必须大于等于父类的方法的访问权限,方法覆盖只能存在于子类和父类之间,子类覆盖方法不能比父类被覆盖方法抛出更多异常
静态变量
-
静态成员和方法也会被继承
-
静态方法只能访问静态成员,不可以访问非静态成员。因为静态方法加载时,优先于对象存在,所以没有办法访问对象中的成员
-
静态方法中不能使用this,super关键字
-
成员变量存在于堆内存中。静态变量存在于方法区中
-
静态代码块、构造代码块、构造函数同时存在时的执行顺序:静态代码块 > 构造代码块 > 构造函数
-
静态代码块在类被加载的时候就运行了,而且只运行一次,并且优先于各种代码块以及构造函数。如果一个类中有多个静态代码块,会按照书写顺序依次执行,比如一个项目启动需要加载的很多配置文件等资源,我们就可以都放入静态代码块中。
class Animal { static { System.out.println("animal 静态代码块"); } { System.out.println("构造代码块"); } }
-
构造代码块在创建对象时被调用,每次创建对象都会调用一次,但是优先于构造函数执行
-
构造函数的命名必须和类名完全相同。在java中普通函数可以和构造函数同名,但是必须带有返回值
final
- 修饰常量,初始化有4种方式
- 1 赋值初始化
- 2 构造代码块初始化
- 3 构造方法初始化
- 4 静态变量静态初始化块中初始化
- 修饰方法时,它表示这个方法不可以被子类重写,但是它这不影响它被子类继承
- final类不允许被继承
多态
父类型的引用可以指向子类的对象,方法重载和方法覆写实际上属于多态性的一种体现,真正的多态性还包括对象多态性的概念。
- Java中除了static和final方法外,其他所有的方法都是运行时绑定的。在我另外一篇文 章中说到private方法都被隐式指定为final的,因此final的方法不会在运行时绑定。当在派生类中重写基类中static、final、或 private方法时,实质上是创建了一个新的方法。
- 在派生类中,对于基类中的private方法,最好采用不同的名字。
- 包含抽象方法的类叫做抽象类。注意定义里面包含这样的意思,只要类中包含一个抽象方法,该类就是抽象类。抽象类在派生中就是作为基类的角色,为不同的子类提供通用的接口。
- 对象清理的顺序和创建的顺序相反,当然前提是自己想手动清理对象,因为大家都知道Java垃圾回收器。
- 在基类的构造方法中小心调用基类中被重写的方法,这里涉及到对象初始化顺序。
- 构造方法是被隐式声明为static方法。
- 用继承表达行为间的差异,用字段表达状态上的变化
抽象
-
使用abstract修饰的类叫做抽象类。抽象类无法实例化
-
使用abstract关键字所修饰的方法叫做抽象方法
-
如果一个类包含了抽象方法,那么这个类一定是抽象类
-
抽象类可以包含具体方法
-
自类继承抽象父类,子类必须要实现父类中所定义的所有抽象方法
public class Syntax3 { public static void main(String[] args) { Tree2 t = new Tree2(); // Tree t1 =new Tree(); t.breathe(); } } abstract class Tree { abstract void breathe(); } class Tree2 extends Tree { @Override void breathe() { System.out.println("a tree ~~~ "); } }
接口
-
java 可以实现多个接口
-
接口中没有构造方法,不能被实例化
-
接口不可以实现接口,但是可以继承接口
-
除非是抽象类,否则必须实现抽象方法
interface interface1 { // 接口的变量 默认就是 public static final int a = 1; // 接口的方法默认就是 public abstract void shout(); }
为什么Java语言不允许多重继承呢?
当子类覆盖父类的实例方法或隐藏父类的成员变量及静态方法时,Java虚拟机采用不同的绑定规则,假如还允许一个类 有多个直接的父类,那么会使绑定规则更加复杂,
因此,为了简化系统结构设计和动态绑定机制,Java语言禁止多重继承.而接口中只有抽象方法,没有实例变量和静态方法,只有接口的实现类才会实现 接口的抽象方法(接口中的抽象方法是通过类来实现的),因此,一个类即使有多个接口,也不会增加Java虚拟机进行动态绑定的复杂度.因为Java虚拟机 永远不会把方法与接口绑定,而只会把方法与它的实现类绑定
main方法
- 是静态方法
- 保证所在类的独立运行。是程序的入口。被jvm调用
- jvm调用main方法时,传递的实际参数是 new String[0]。
创建一个对象都在内存中做了什么事情?
Person p = new Person();
1:先将硬盘上指定位置的Person.class文件加载进内存。
2:执行main方法时,在栈内存中开辟了main方法的空间(压栈-进栈),然后在main方法的栈区分配了一个变量p。
3:在堆内存中开辟一个实体空间,分配了一个内存首地址值。new
4:在该实体空间中进行属性的空间分配,并进行了默认初始化。
5:对空间中的属性进行显示初始化。
6:进行实体的构造代码块初始化。
7:调用该实体对应的构造函数,进行构造函数初始化。()
8:将首地址赋值给p ,p变量就引用了该实体。(指向了该对象)
包装类
可以直接处理基本类型的,但是在有些情况下我们需要将其作为对象来处理,这时就需要将其转化为包装类了.包装类的共同方法
- 带有基本值参数并创建包装类对象的构造函数.如可以利用Integer包 装类创建对象,Integer obj=new Integer(145);
- 带有字符串参数并创建包装类对象的构造函数.如new Integer(“45”);
- 生成字符串表示法的toString()方法,如obj.toString().
- 对同一个类的两个对象进行比较的equals()方法,如obj1.eauqls(obj2);
- 生成哈稀表代码的hashCode方法,如obj.hasCode();
- 将字符串转换为基本值的 parseType方法,如Integer.parseInt(args[0]);
- 可生成对象基本值的typeValue方法,如obj.intValue();
包装类的自动装箱,自动拆箱
装箱,就是把基本类型用它们相对应的引用类型包起来,使它们可以具有对象的特质,如我们可以把int型包装成Integer类的对象
拆箱,就是跟装箱的方向相反,将Integer及Double这样的引用类型的对象重新简化为值类型的数据
编译器在编译时期依您所编写的方法,决定是否进行装箱或拆箱动作
java源码对int的处理
java为了提高效率,IntegerCache类中有一个数组缓存 了值从-128到127的Integer对象。当我们调用Integer.valueOf(int i)的时候,如果i的值是>=-128且<=127时,会直接从这个缓存中返回一个对象,否则就new一个Integer对象
集合
- List、Set、Map是这个集合体系中最主要的三个接口。
- 其中List和Set继承自Collection接口。
interface Collection { boolean add(Object o); boolean remove(Object o); int size(); boolean isEmpty(); boolean contains(Object o); boolean containsAll(Collection c); boolean addAll(Collection c); void clear(); void removeAll(Collection c); Object[] toArray(); }
- Set不允许元素重复,HashSet和TreeSet是两个主要的实现类。
- List有序且允许元素重复,ArrayList、LinkedList和Vector是三个主要的实现类。ArrayList从其命名中可以看出它是一种类似数组的形式进行存储,因此它的随机访问速度极快,而 LinkedList的内部实现是链表,它适合于在链表中间需要频繁进行插入和删除操作。
interface List extends Collection { void add(int index, Object element);// 在指定位置index上添加元素element boolean addAll(int index, Collection c);// 将集合c的所有元素添加到指定位置index Object get(int index);// 返回List中指定位置的元素 int indexOf(Object o);// 返回第一个出现元素o的位置,否则返回-1 int lastIndexOf(Object o); //返回最后一个出现元素o的位置,否则返回-1 Object remove(int index);//删除指定位置上的元素 Object set(int index, Object element);//用元素element取代位置index上的元素,并且返回旧的元素 } class LinkedList { void addFirst(Object o);// 将对象o添加到列表的开头 void addLast(Object o);//将对象o添加到列表的结尾 Object getFirst(); //返回列表开头的元素 Object getLast(); //返回列表结尾的元素 Object removeFirst(); //删除并且返回列表开头的元素 Object removeLast():删除并且返回列表结尾的元素 LinkedList(); //构建一个空的链接列表 LinkedList(Collection c);// 构建一个链接列表,并且添加集合c的所有元素 }
- Map也属于集合系统,但和Collection接口不同。Map是key对value的映射集合,其中key列就是一个集合。key不能重复,但是value可以重复。HashMap、TreeMap和Hashtable是三个主要的实现类。
- SortedSet和SortedMap接口对元素按指定规则排序,SortedMap是对key列进行排序
ArrayList
ArrayList类封装了一个动态再分配的Object[]数组。每个ArrayList对象有一个capacity。这个capacity表示存储列表中元素的数组的容量。当元素添加到ArrayList时,它的capacity在常量时间内自动增加。
在向一个ArrayList对象添加大量元素的程序中,可使用ensureCapacity方法增加capacity。这可以减少增加重分配的数量。
- void ensureCapacity(int minCapacity): 将ArrayList对象容量增加minCapacity
- void trimToSize(): 整理ArrayList对象容量为列表当前大小。程序可使用这个操作减少ArrayList对象存储空间
流
Java中的流是对字节序列的抽象
File类
// 文件操作
File file = new File("d:" + File.separator+"a.txt");
//默认不存在返回false 再执行一次true
System.out.println(file.exists());
//默认创建返回true,再执行一次false
System.out.println(file.createNewFile());
// 是否是文件
System.out.println(file.isFile());
System.out.println(file.isDirectory());
System.out.println(file.canRead());
System.out.println(file.canWrite());
// 文件大小
System.out.println(file.length());
File f1 = new File("d:/tmp/one/two/three");
if(f1.mkdirs()){
System.out.println("创建ok");
}else {
System.out.println("本身就有");
// 删除不成功,因为只能直接删除一层
f1.delete();
// 删除动作交给系统完成。无论是否反生异常,系统在退出时执行删除动作
f1.deleteOnExit();
}
// 重命名
File f1 = new File("c:\\a.txt");
File f2 = new File("c:\\b.txt");
f1.renameTo(f2);//将c盘下的a.txt文件改名为b.txt文件
// 返回的是目录下的文件名称
List l1 = Arrays.asList(file1.list());
// 返回的是目录下的文件对象
List l2 = Arrays.asList(file1.listFiles());
for(int a =0; a< l1.size(); a++){
System.out.println(l1.get(a));
}
字节流
- Java中的字节流处理的最基本单位为单个字节,它通常用来处理二进制数据。
- 字节流可以处理所有类型数据,如图片,mp3,avi
- Java中最基本的两个字节流抽象类是InputStream和OutputStream,它们分别代表了组基本的输入字节流和输出字节流
字符流
- Java中的字符流处理的最基本的单元是Unicode码元(大小2字节)
- 它通常用来处理文本数据,最基本的两个类,是reader和writer
Reader
// int read():读取一个字符。返回的是读到的那个字符。如果读到流的末尾,返回-1.
// int read(char[]):将读到的字符存入指定的数组中,返回的是读到的字符个数,也就是往数组里装的元素的个数。如果读到流的末尾,返回-1.
// close():读取字符其实用的是window系统的功能,就希望使用完毕后,进行资源的释放
class FileReader
public class Steam1 {
public static void main(String[] args) throws IOException {
FileReader fr = null;
String file1 = "C:\\Users\\ASUS\\Desktop\\langs\\note.txt";
String file2 = "C:/Users/ASUS/Desktop/langs/note.txt";
try {
fr = new FileReader(file2);
//该长度通常都是1024的整数倍。
char[] buf = new char[1024];
int len = 0;
while((len=fr.read(buf))!=-1){
System.out.println(new String(buf,0,len));
}
} catch(IOException e) {
System.out.println(e.toString());
}
}
}
BufferedReader
readLine():方法原理, 用的还是与缓冲区关联的流对象的read方法。只不过,每一次读到一个字符,先不进行具体操作,先进行临时存储。当读取到回车标记时,将临时容器中存储的数据一次性返回
// BufferedReader 按行读取数据
BufferedReader br = new BufferedReader(new FileReader("buf.txt"));
String line = null;
while((line=br.readLine())!=null){
System.out.println(line);
}
br.close();
Writer
// write(ch): 将一个字符写入到流中。
// write(char[]): 将一个字符数组写入到流中。
// write(String): 将一个字符串写入到流中。
// flush():刷新流,将流中的数据刷新到目的地中,流还存在。
// close():关闭资源:在关闭前会先调用flush(),刷新流中的数据去目的地。然流关闭
BufferedWriter bufw = new BufferedWriter(new FileWriter("buf.txt"));
bufw.write("abce");//将数据写入到了缓冲区。
bufw.flush();//对缓冲区的数据进行刷新。将数据刷到目的地中。
bufw.close();//关闭缓冲区,其实关闭的是被包装在内部的流对象。
字节流的read()方法读取一个字节
为什么返回的不是byte类型,而是int类型呢?
因为read方法读到末尾时返回的是-1,而在所操作的数据中的很容易出现连续多个1的情况,而连续读到8个1,就是-1,导致读取会提前停止。所以将读到的一个字节给提升为一个int类型的数值,但是只保留原字节,并在剩余二进制位补0.
对于write方法,可以一次写入一个字节,但接收的是一个int类型数值。只写入该int类型的数值的最低一个字节(8位)。简单说:read方法对读到的数据进行提升。write对操作的数据进行转换
转换流:
1,是字节流和字符流之间的桥梁。
2,该流对象中可以对读取到的字节数据进行指定编码表的编码转换
// 通过该构造函数初始化,可以指定编码表 不传默认gbk
InputStreamReader(InputStream,String charSet):
// 通过该构造函数初始化,可以指定编码表 不传默认gbk
OutputStreamWriter(OutputStream,String charSet)