Java关键字
idea快捷键
常用快捷键
1.ctrl+alt+t 将代码快用try catch包裹
Java位运算详解
Java位运算符有 & | ^ ~四种
A=0011 1100
B=0000 1101
A&B=0000 1100 A与B逐位比较两个位1则为1,否则为0 与
A|B=0011 1101 A与B逐位比较有一个为1则为1,否则为0 或
A^B=0011 0001 如果两个相同则为0,否则为1 异或
~A=1100 0011 对A进行取反 非
2<<3 2进行左移3位得到的结果是16
16>>3 得到结果是2
Java可变参数
Java可变参数定义方式为 声明一个变量类型后跟省略号,可变参数必须为参数列表的最后一个参数
public void test(int... k){
if(k.length> 0){
for(int i=0; i< k.length; i++){
System.out.println("i"+k[i])
}
}
}
Java稀疏数组
数组中非零元素的个数远远小于数组元素的总数,并且非零元素的分布没有规律,通常认为数组中非零元素的总数比上数组所有元素总数的值小于等于0.05时,则称该数组为稀疏数组(sparse matrix)
0 | 0 | 0 | 0 | 0 |
---|---|---|---|---|
0 | 1 | 0 | 0 | 0 |
0 | 0 | 2 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 |
将上面数组转化为如下数组存储:
552代表的是原始数组是5行,5列,2两个有效值
111代表的是原始数组第一行第一列存的值为1
222代表的是原始数组第二行第二列存的值为2
5 | 5 | 2 |
---|---|---|
1 | 1 | 1 |
2 | 2 | 2 |
稀疏数组示例代码
//定义一个原始数组
int[] [] qp = new int[5][5];
qp[1][1]=1;
qp[2][2]=2;
//原始数组打印
for (int[] ints : qp) {
for (int anInt : ints) {
System.out.print(anInt + "\t");
}
System.out.println();
}
System.out.println("############################");
//算出原始数组有多少个有效值
int countvalue=0;
for (int[] ints : qp) {
for (int anInt : ints) {
if(anInt != 0){
countvalue+=1;
}
}
}
//转化为稀疏数组
int[][] xs = new int[countvalue+1][3];
xs[0][0]=qp.length;
xs[0][1]=qp[1].length;
xs[0][2]=countvalue;
int count=1;
for (int i = 0; i < qp.length; i++) {
for (int i1 = 0; i1 < qp[i].length; i1++) {
if(0 != qp[i][i1]){
xs[count][0]=i;
xs[count][1]=i1;
xs[count][2]=qp[i][i1];
count++;
}
}
}
//输出稀疏数组
for (int[] x : xs) {
for (int i : x) {
System.out.print(i+"\t");
}
System.out.println();
}
System.out.println("###################################");
//将稀疏数组还原为原始数组
int[][] hyqp= new int[xs[0][0]][xs[0][1]];
for (int i = 0; i < hyqp.length; i++) {
for (int i1 = 1; i1 < xs.length; i1++) {
hyqp[xs[i1][0]][xs[i1][1]]=xs[i1][2];
}
}
//输出还原后的稀疏数组
for (int[] ints : hyqp) {
for (int anInt : ints) {
System.out.print(anInt+"\t");
}
System.out.println();
}
上面代码的输出结果如下:
0 0 0 0 0
0 1 0 0 0
0 0 2 0 0
0 0 0 0 0
0 0 0 0 0
############################
5 5 2
1 1 1
2 2 2
###################################
0 0 0 0 0
0 1 0 0 0
0 0 2 0 0
0 0 0 0 0
0 0 0 0 0
Process finished with exit code 0
Java注解
元注解
- @Target 目标标注该注解作用范围有(TYPE、FIELD、METHOD、PARAMETER、CONSTRUCTOR、LOCAL_VARIABLE、ANNONATION_TYPE、PACKAGE、TYPE_PARAMETER、TYPE_USE) 在上面这些地方使用
- @Retention 标识在什么级别注解信息有效 级别范围有 (SOURCE、CLASS、RUNTIME) 一般都会写RUNTIME在运行时该注解依旧有效
- @Documented 文档注解
- @Inherited 子类可以继承父类的注解
自定义注解示例代码
//使用自定义对类约束的注解,并且传递一个值
@MyAnnotation2("table1")
public class AnnotationTest {
//使用自定义对字段约束的注解,并且传递三个注解需要传递的值
@MyAnnotation(filedname = "id",filedtype = "int",filedlength = 10)
private int id;
//使用自定义对方法约束的注解,并且使用默认值
@MyAnnotation2
public int test(){
return this.id;
}
}
//注解的作用对象为字段
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
String filedname();
String filedtype();
int filedlength();
}
//注解的作用对象是类和方法,并且默认值为空
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
String value() default "";
}
Java反射
Java反射机制提供的功能
-
在运行时判断任意一个对象所属的类
-
在运行时构造任意一个类的对象
-
在运行时判断任意一个类的成员变量和方法
-
在运行时获取泛型信息
-
在运行时调用任意一个对象的成员变量和方法
-
在运行时处理注解
-
生成动态代理
反射的优缺点
有点:可以实现动态创建对象和编译,体现出很大灵活性
缺点:对性能有影响。使用反射基本上是一种解释操作,这种操作总是慢于直接执行的操作。
反射的几种获取方式
-
通过反射获取类的class对象
Class c= Class.forName(“org.apache.test.User”);
-
通过类点class获得
Class c2= User.class;
-
通过实例化对象的getClass方法获得
Class c3= user.getClass(); -
基本类型的包装类通过点type属性获得
Class type = Boolean.TYPE;
-
获得父类类型
Class<?> superclass = calculator.getSuperclass();
Class类
- Class本身也是一个类
- Class对象只能有系统建立对象
- 一个加载的类在JVM中只会有一个.class文件
- 每个类的实例都会记得自己是有哪个Class实例所生成
- 通过Class可以完整地得到一个类中所有被加载的结构
- Class类是Reflection的根源,针对任何想动态加载、运行的类,唯有先获得相应的Class对象
Java内存分析
堆
- 存放new出来的对象
- 存放数组
- 可以被所有线程共享
栈
- 存放基本变量类型(包含基本类型的具体数值)
- 引用对象变量(会存放该引用在堆里的具体地址)
方法区
- 包含了所有的class
- static变量
- 可以被所有线程共享
类加载过程
加载
”加载“是”类加机制”的第一个过程,在加载阶段,虚拟机主要完成三件事:
-
通过一个类的全限定名来获取其定义的二进制字节流
-
将这个字节流所代表的的静态存储结构转化为方法区的运行时数据结构
-
在堆中生成一个代表这个类的Class对象,作为方法区中这些数据的访问入口
将类的class文件读入到内存中,并为之创建一个java.lang.Class对象
连接
-
验证
验证的主要作用就是确保被加载的类的正确性。也是连接阶段的第一步。说白了也就是我们加载好的.class文件不能对我们的虚拟机有危害,所以先检测验证一下。他主要是完成四个阶段的验证:
- 文件格式的验证:验证.class文件字节流是否符合class文件的格式的规范,并且能够被当前版本的虚拟机处理。这里面主要对魔数、主版本号、常量池等等的校验(魔数、主版本号都是.class文件里面包含的数据信息、在这里可以不用理解)。
- 元数据验证:主要是对字节码描述的信息进行语义分析,以保证其描述的信息符合java语言规范的要求,比如说验证这个类是不是有父类,类中的字段方法是不是和父类冲突等等。
- 字节码验证:这是整个验证过程最复杂的阶段,主要是通过数据流和控制流分析,确定程序语义是合法的、符合逻辑的。在元数据验证阶段对数据类型做出验证后,这个阶段主要对类的方法做出分析,保证类的方法在运行时不会做出危害虚拟机安全的事。
- 符号引用验证:它是验证的最后一个阶段,发生在虚拟机将符号引用转化为直接引用的时候。主要是对类自身以外的信息进行校验。目的是确保解析动作能够完成。
-
准备
准备阶段主要为类变量分配内存并设置初始值。这些内存都在方法区分配。在这个阶段我们只需要注意两点就好了,也就是类变量和初始值两个关键词:
-
类变量(static)会分配内存,但是实例变量不会,实例变量主要随着对象的实例化一块分配到java堆中
-
这里的初始值指的是数据类型默认值,而不是代码中被显示赋予的值。比如
public static int value = 1; //在这里准备阶段过后的value值为0,而不是1。赋值为1的动作在初始化阶段。
-
-
解析
解析阶段主要是虚拟机将常量池中的符号引用转化为直接引用的过程。什么是符号应用和直接引用呢?
- 符号引用:以一组符号来描述所引用的目标,可以是任何形式的字面量,只要是能无歧义的定位到目标就好,就好比在班级中,老师可以用张三来代表你,也可以用你的学号来代表你,但无论任何方式这些都只是一个代号(符号),这个代号指向你(符号引用)
- 直接引用:直接引用是可以指向目标的指针、相对偏移量或者是一个能直接或间接定位到目标的句柄。和虚拟机实现的内存有关,不同的虚拟机直接引用一般不同。
初始化
这是类加载机制的最后一步,在这个阶段,java程序代码才开始真正执行。我们知道,在准备阶段已经为类变量赋过一次值。在初始化阶端,程序员可以根据自己的需求来赋值了。一句话描述这个阶段就是执行类构造器< clinit >()方法的过程。
在初始化阶段,主要为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。在Java中对类变量进行初始值设定有两种方式:
①声明类变量是指定初始值
②使用静态代码块为类变量指定初始值
JVM初始化步骤
1、假如这个类还没有被加载和连接,则程序先加载并连接该类
2、假如该类的直接父类还没有被初始化,则先初始化其直接父类
3、假如类中有初始化语句,则系统依次执行这些初始化语句
类初始化时机:只有当对类的主动使用的时候才会导致类的初始化,类的主动使用包括以下几种:
- 创建类的实例,new一个对象
- 对静态变量赋值调用类的静态方法反射(如 Class.forName(“com.shengsiyuan.Test”))对类进行反射调用
- Java虚拟机启动时被标明为启动类的类,也就是main方法所在的类
- 初始化子类如果父类没有被初始化也会初始化父类
- 调用类的静态成员和方法
类加载器
-
启动类加载器
启动类加载器无法直接获取,用c++编写的
-
拓展类加载器
拓展类加载器父类为启动类加载器
-
应用程序类加载器
应用程序类加载器父类为拓展类加载器
反射使用示例
package com.taiji.activiti7.test;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
public class ReflectionTest {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获取类的Class对象
Class<?> aClass = Class.forName("com.taiji.activiti7.test.User");
//获得User类的实例,用的是无参构造器
User o = (User)aClass.newInstance();
System.out.println(o);
//通过构造器创建对象
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(int.class, int.class, String.class);
//通过有参构造器获取User类的实例
Object user = declaredConstructor.newInstance(1, 18, "张三");
System.out.println(user);
//通过无参构造器创建对象
Constructor<?> declaredConstructor1 = aClass.getDeclaredConstructor();
Object user1 = declaredConstructor1.newInstance();
System.out.println(user1);
//通过反射获得普通方法
Method test = aClass.getDeclaredMethod("test");
//执行方法
test.invoke(user);
//通过反射调用有参方法 第一个参数为方法名, 第二个参数开始为方法名里对应的参数列表
Method test2 = aClass.getDeclaredMethod("test2", int.class, int.class, String.class);
//invoke参数解释 第一个参数是调用对象user对象 第二个参数开始为方法参数 result为方法返回值
Object result = test2.invoke(user,1, 20, "李四");
System.out.println(result);
//通过反射获取类的私有属性,并操作其值
//1.获取需要操作的字段
Field name = aClass.getDeclaredField("name");
//2.将操作该字段的权限设置true
name.setAccessible(true);
//3.设置对象的属性值
name.set(o,"王五");
//4.打印测试设置对象的属性值是否成功
System.out.println(o.getName());
//反射操作泛型
//1.获取带泛型类型的方法
Method test3 = aClass.getMethod("test3", Map.class, User.class);
//2.获取方法泛型参数列表
Type[] genericParameterTypes = test3.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
//参数列表一级类型
System.out.println("方法参数"+genericParameterType);
//参数列表泛型中包装的类型,也就是Map里面的类型
if(genericParameterType instanceof ParameterizedType){
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println("泛型里的参数"+actualTypeArgument);
}
}
}
//返回值为泛型的返回值类型获取
Type genericReturnType = test3.getGenericReturnType();
System.out.println(genericReturnType);
//反射获取注解信息
//1.获取类名上的注解信息
mytable mytable = aClass.getAnnotation(mytable.class);
System.out.println("类上的注解信息是"+mytable.value());
//2.获取字段上的注解 需要指定是哪个字段 下面以age字段为例
Field age = aClass.getDeclaredField("age");
fieldann annotation = age.getAnnotation(fieldann.class);
System.out.println("字段上注解的columnName是"+annotation.columnName());
System.out.println("字段注解的lenght是"+annotation.lenght());
System.out.println("字段注解的type是"+annotation.type());
}
}
@mytable("db_user")
class User{
@myInterface(1)
private int id;
@fieldann(columnName = "age",type = "int",lenght = 10)
private int age;
private String name;
public void test(){
System.out.println("这是个测试方法");
}
public User() {
}
public User(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
public String test2(int id,int age,String name){
System.out.println("编号为"+id+"的人名叫"+name+"年龄"+age);
return "ok";
}
public Map test3(Map<String,User> map,User u){
return new HashMap();
}
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface myInterface{
int value();
}
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface mytable{
String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface fieldann{
String columnName();
String type();
int lenght();
}