Java 语言对我来说即熟悉又陌生的语言,原来是特别喜欢Java,就觉得它是世界最好的语言。 设计的规范非常好,代码看起来非常完整,还有巨大的组件/jar库。 总之来说是非常强大。 随着几年没有接触过它,慢慢就忘记它了。 就好比一辆车,之前一直经常开觉得很顺手,现在重新开起发现当年的感觉比较难找到了。【重拾JAVA】
根据java的语法生成java文件/类文件,然后通过javac 工具,直接把java文件加载到JVM,然后生成字节码。 应用请求JRE环境,JRE把class执行结果返回给应用。
Java SE: CLI 请求JRE环境->调用/生成class文件->调用本地库->输出
Java语言的解析器,可以把类文件编译生成class文件的过程。总的过程:1. 归类: 把执行的对象和变量/对象申请内存块,放到heap里面,把方法放到方法区域; 2.解析和执行过程:对于类文件,先编译,如果有存在空对象/空指针等报错会抛出人释放内存,执行完后垃圾回收内存;3. 调用本地系统的方法,如文件,I/O等方法,生成class 文件。
类加载的主要思路:对于引用的类,会先在classpath配置里面找找到就会加载,不然继续向上找,知道找到rt.jar,如果还不存在,这报错"ClassNotFoundException"
总的来说:加载class文件->验证->分配内存空间->符号解析,变量、常量池->初始化可以使用了
Java 基础知识就是怎么根据Java API生成java类文件。 Java API包含了组件/工具如下图结构描述:
Java知识结构
Java SE相关文档
对象里面包含了属性和方法,通过Main函数启动CLI 进程来执行对类文件的解析。
public class Bicycle { int speed = 1; int gear = 1; public void addSpeed(int value){ this.speed += value; } public int getSpeed(){ return this.speed; } public int getGear(){ return this.gear; } } public class Main { public static void main(String[] args) { System.out.println("Hello World!"); Bicycle b = new Bicycle(); b.addSpeed(3); b.addSpeed(4); System.out.println("Speed value :"+b.getSpeed()); System.out.println("Gear value :"+b.getGear()); } } 复制代码
public class RoadBicycle extends Bicycle { private int road =1; public void setRoad(int val){ this.road += val; //增加加速值 this.road += this.getGear(); } public int getRoad(){ return this.road; } } 复制代码
public class Disk implements Circle{ private int weight = 100; public void setWeight(){ this.weight += 10; } public int getLength() { return this.weight/3; } public int getRadius() { return this.weight/2; } } 复制代码
public int[] getArray(){ int [] anArray = new int [10];; for(int i=0; i<10; i++) { anArray[i] = i+10; } return anArray; } 复制代码
public void invokeCalculator(){ Calculator myApp = new Calculator(); IntegerMath addition = (a, b) -> a + b; IntegerMath subtraction = (a, b) -> a - b; System.out.println("40 + 2 = " + myApp.operateBinary(40, 2, addition)); System.out.println("20 - 10 = " + myApp.operateBinary(20, 10, subtraction)); } 复制代码
注解是一种元数据形式,提供有关不属于程序本身的程序的数据。注解对他们注释的代码的操作没有直接的影响。
注解的作用:
注解可以声明字段,类,方法,属性等
@Target: 说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。
@Retention定义了该Annotation被保留的时间长短 : 1.SOURCE:在源文件中有效;2.CLASS:在class文件中有效;3.RUNTIME:在运行时有效
@Documented : 用于描述其它类型的annotation应该被作为被标注的程序成员的公共API
@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。
定义注解格式:
public @interface 注解名 {定义体} 复制代码
泛型的作用:在定义类,接口和方法时,泛型使类型(类和接口)成为参数。
常用的类型参数
E - Element (used extensively by the Java Collections Framework) K - Key N - Number T - Type V - Value S,U,V etc. - 2nd, 3rd, 4th types 复制代码
public class OrderedPair<K, V> implements Pair<K, V> { private K key; private V value; public OrderedPair(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } } public interface Pair<K, V> { public K getKey(); public V getValue(); } //泛型的处理 Pair<String, Integer> p1 = new OrderedPair<String, Integer>("Even", 8); System.out.println("Generic key :" + p1.getKey() + " , value :" + p1.getValue()); 复制代码
提供了一种包命名的方式
捕获异常,异常的处理一般在文件,I/O,数据库,这些地方存在各种不确定的情况,影响其中断。
// 捕获异常 try { } catch (IndexOutOfBoundsException e) { System.err.println("IndexOutOfBoundsException: " + e.getMessage()); } catch (IOException e) { System.err.println("Caught IOException: " + e.getMessage()); } //扔出异常 public Object pop() { Object obj; if (size == 0) { throw new EmptyStackException(); } obj = objectAt(size - 1); setObjectAt(size - 1, null); size--; return obj; } 复制代码
I 表示输入流, O 表示输出流
I/O 流主要的方式
I/O采用很多设计模式,流是解决获取数据的加载到内存缓存区问题 , Writer主要是解决流的序列化/存储的问题
流的类型包括:
public boolean write(String sourceFileName, String targetFileName) throws IOException{ FileReader inputStream = null; FileWriter outputStream = null; try { System.out.println("Now sourceFile :" +sourceFileName + " , targetFileName: "+ targetFileName); inputStream = new FileReader(sourceFileName); outputStream = new FileWriter(targetFileName); int c; while ((c = inputStream.read()) != -1) { outputStream.write(c); } // return true; } finally { if (inputStream != null) { inputStream.close(); } if (outputStream != null) { outputStream.close(); } return false; } } 复制代码
在并发编程中,有两个基本的执行单元:进程和线程,一个进程有一个独立的执行环境。一个进程通常具有一套完整的私有基本运行时资源; 特别是每个进程都有自己的内存空间。所以处理大并发的事情,更多的是关系进程或者线程对服务器资源的压力。包括CPU, 内存等
现在启动的方式主要有两种,一种是实现Runable接口,另一种是继承Thread
// 每个线程都继承了Runnable方法,每个方法都考虑执行的效果 public class HelloRunnable implements Runnable { public void run() { System.out.println("Hello from a thread!"); } public static void main(String args[]) { (new Thread(new HelloRunnable())).start(); } } // 继承Thread的方式 public class HelloThread extends Thread { public void run() { System.out.println("Hello from a thread!"); } public static void main(String args[]) { (new HelloThread()).start(); } } 复制代码
这个存在问题就是如果出现一个资源获得了锁,另外一个资源确一直没有释放锁,就出现死锁的情况。 这样就需要考虑资源的sleep和必要的中断
public class Test { public static void main(String[] args) { ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(5)); for(int i=0;i <15 ; i++){ MyTask myTask = new MyTask(i); executor.execute(myTask); System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+ executor.getQueue().size()+",已执行玩别的任务数目:"+executor.getCompletedTaskCount()); } executor.shutdown(); } } class MyTask implements Runnable { private int taskNum; public MyTask(int num) { this.taskNum = num; } @Override public void run() { System.out.println("正在执行task "+taskNum); try { Thread.currentThread().sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("task "+taskNum+"执行完毕"); } } 复制代码
支持对系统的属性使用Key和value的方式crud。Properties继承了java.util.Hashtable, 可以使用其一些属性特性
主要是Java的工具包获取,Pattern.compile
Console console = System.console(); if (console == null) { System.err.println("No console."); System.exit(1); } while (true) { Pattern pattern = Pattern.compile(console.readLine("%nEnter your regex: ")); Matcher matcher = pattern.matcher(console.readLine("Enter input string to search: ")); boolean found = false; while (matcher.find()) { console.format("I found the text" + " /"%s/" starting at " + "index %d and ending at index %d.%n", matcher.group(), matcher.start(), matcher.end()); found = true; } if(!found){ console.format("No match found.%n"); } } 复制代码
集合拆分成三种方式:List(数组列表) ,Set(不允许有重复元素的集合) ,Map(key和value 集合).Queue也是其中的一种方式
数据结构
算法
主要使用LocalTime 获取时间的操作
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM d yyyy"); LocalDate date = LocalDate.parse(input, formatter); System.out.printf("%s%n", date); 复制代码
反射机制本质就是根据地址块,如对象,类,方法的地址块去检查或者修改其行为。 主要的机制是java 虚拟机可以通过命名空间+类名对内存块的使用。 并且所有类/对象都有其自身的元数据包括public,private,属性等情况。
好的地方主要是可以外部调用,如调试,开发工具,Spring的根据类名获取对象,不好的地方主要是性能消耗大,并且可能会影响一些安全
通过运行时加载该类,然后找到这个类的方法和域(一般是解析字节码获得到类相关的元数据),生成列表信息,最后动态加载该类。
网络一般真正处理是专注于讲应用层的数据传递到TCP 层,然后通过IP协议转换
数据包的内容
Socket 通信架构
Socket是解决数据两种,一种是发数据,一种是接受数据,都是通过ip+端口的绑定,服务端是通过循环监听客户端的Socket数据
public void run() { try { BufferedReader br = new BufferedReader(new InputStreamReader(socket .getInputStream())); while (true) { String msg = br.readLine(); if ("exit".equalsIgnoreCase(msg)) break; System.out.println("(" + socket.getInetAddress().getHostAddress() + ":" + socket.getPort() + "):" + msg); } br.close(); socket.close(); } catch (Exception e) { e.printStackTrace(); } } 复制代码
Http一般有建立连接,发送请求和接受请求,最后关闭三个过程,如果很长时间才关闭通道,才关闭这算长连接,否则处理完就关闭,算短连接。
远程方法调用这种方式适合内部机器的通信,但是考虑到系统兼容性这种方式也不太好,最后一般会采用内部的http的通信或者采用webserivce的方式。 主要是通过注册了这个方法,然后远程根据方法的参数和规范,来调用。 应该也是采用RPC的规范来走的。
方便的是可以针对java语言搞分布式计算跟语言绑定,可以在虚拟机注册列表里面调用任何的注册服务,但是这个依赖性太强了。后期的protobuf方式就是对现有的替代了。 - 动态代码加载的优点: 通过注册类的方式来动态加载 - 可以调用远程接口和方法: 主要是通过RPC/TCP协议来处理 - 使用RMI创建分布式应用程序 :可以把 - 可以建立分布式应用: 计算引擎
)
主要是对于java的产品提供安全的认证,包括数字签名
JDBC 主要解决了,JAVA提供的数据库驱动API,这样只要导入了对应的驱动文件,就可以调用其服务哦。
public void connectToAndQueryDatabase(String username, String password) { Connection con = DriverManager.getConnection( "jdbc:myDriver:myDatabase", username, password); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1"); while (rs.next()) { int x = rs.getInt("a"); String s = rs.getString("b"); float f = rs.getFloat("c"); } } 复制代码
开发工具: (在bin/子目录中)将帮助您开发,执行,调试和编写以Java编程语言编写的程序的工具和实用程序。有关更多信息,请参阅工具文档。
运行环境: (在jre/子目录中)由JDK使用的Java运行时环境(JRE)的实现。JRE包含一个Java虚拟机(JVM™),类库和其他支持执行用Java编程语言编写的程序的文件。
额外的库: (在lib/子目录中)开发工具所需的其他类库和支持文件。
Java DB: (在db/子目录中)Java DB,Oracle分布的Apache Derby关系数据库。有关更多信息,请参阅文档。
C文件头: (在include/子目录中)使用Java本地接口,JVM工具接口和Java平台的其他功能支持本地代码编程的头文件。
源代码:(In src.zip)构成Java核心API的所有类的Java编程语言源文件。使用:jar xvf src.zip
javac字节码编译器:
由以下文件组成的动态连接机制:
Java密码扩展:
Java EE: 应用(浏览器/其他Clent)发送http请求 -> 服务器(tomcat/nginx)-> Java CGI -> 请求JRE环境->调用/生成class文件->调用本地库->输出
是在前面RMI发展而来的。 支持满足企业级开发的方式。 但是标准一致很高,特别是EJB非常难上手,并且关联的东西非常多。最后,Spring 以j2EE标准基础上专门切入Bean管理也即是EJB的轻量版本(Model层),然后迅速占领J2EE的开发框架重要地位,并且慢慢的把controller(Struct)解决了。甚至对V层也有一定的组件和扩展。 就出现了Spring MVC 框架。最后为了解决EJB分布式开发部署的成本问题,开发了Spring Boot 满足开发的需求。
主要是采用mvc的机制,最后通过Dao层去读取数据库
Maven 本质是解决jar包的统一管理的问题,这样避免每个项目之前还要下载大量的jar,并且有的时候还需要去找jar很麻烦的。 之前有类似的网站可以下载到各种jar包你根据名字搜索就好,但是一个个下载不方便。 基于解决这类问题出现了maven. 其实每种语言都有类似的工具,如php 有Composer, python 有pip
Tomcat 是服务器主要的是监听某个端口的服务器,Tomcat会自动读取webapps 下的war文件。 而war文件Tomcat 会自动把java语言的代码根据j2EE的规范来生成war包。
对于多个应用的部署,本地可以使用{DOMAIN_NAME}/{app} 来管理多个项目,如果是线上,可以采用Nginx +Tomcat的方式,Nginx 负责分发,Tomcat负责启动多个服务来监听Nginx的服务。
idea 和 Tomcat 关系: idea 使用Tomcat 把web代码生成war包,然后浏览器可以通过tomcat解析和处理这个war
github的wiki 有详细的解释
解决方式:把maven 类文件重新配置下,对于存在冲突的库去掉,然后重新导入下
java.lang.NoSuchMethodError: org.springframework.util.ClassUtils.isPresent(Ljava/lang/String;Ljava/l 复制代码
nginx: [error] invalid PID number "" in "/usr/local/var/run/nginx.pid" 复制代码
## 解决 Mac 下配置环境变量在 ZSH 中无效的问题 在终端中输入: cat ~/.zshrc 以此来查看 .zshrc 文件, 找到里面的 “ # User configuration “ 部分. 可以看到当前 zsh 支持的所有本地已配置环境变量. ## 输入gradle home和path 目录 GRADLE_HOME=/usr/local/Cellar/gradle/4.4; export GRADLE_HOME export PATH=$PATH:$GRADLE_HOME/bin 复制代码
应该使用如下路径进行设置:/usr/local/Cellar/gradle/2.4/libexec ,问题的关键就是路径要有 libexec 复制代码