java基础

本文详细探讨了Java的基础知识,包括I/O流、反射、文件操作、类加载器、注解、阿里巴巴编码规范等内容。讲解了File、InputStream、URL、Resource的区别,流的关闭与flush方法,反射中的类加载器机制,以及类、接口和类加载器的关系。还涵盖了类的生命周期、获取Class对象的方法、异常处理、设计模式和Java 8的新特性。文章深入浅出,适合Java初学者和开发者巩固基础知识。
摘要由CSDN通过智能技术生成

目录

I/O

File、InputStream、URL、Resource的区别???
io流writer写时,若不关闭流,会出现什么;reader需要关闭吗

数据写不进去,其实手动writer.flush(),也可以将数据刷新进去
reader也需要关闭

flush方法应该怎么用

当有大量数据需要写入时,要分批进行writer.flush一下,否则缓存压力过大

FileWriter的write方法源码
FileWriter extends OutputStreamWriter

OutputStreamWriter extends Writer{
	final StreamEncoder se;
	public void write(char cbuf[], int off, int len) throws IOException {
        se.write(cbuf, off, len);
    }
    
	public void flush() throws IOException {
        se.flush();
    }
}

class nio.StreamEncoder extends Writer {
}
nio对普通IO的优化???
BufferedWriter源码
class BufferedWriter extends Writer {
	Writer out;
	char cb[];

	public void write(String s, int off, int len) throws IOException {
        synchronized (lock) {
            ensureOpen();
            int b = off, t = off + len;
            while (b < t) {     
            	// 不停往cb里面填数据      
                s.getChars(b, b + d, cb, nextChar);
                // 当数据超出一个临界值时,会自动先out.write(cb, 0, nextChar);
                if (nextChar >= nChars)
                    flushBuffer();
            }
        }
    }

	public void flush() throws IOException {
        synchronized (lock) {
            flushBuffer();
            out.flush();
        }
    }

	void flushBuffer() throws IOException {
        synchronized (lock) {
            ensureOpen();
            if (nextChar == 0)
                return;
            out.write(cb, 0, nextChar);
            nextChar = 0;
        }
    }

}
read()方法读出的是什么,read(char[] chars)呢
reader = new FileReader(file);
//一个数字,ASCII码,可以强制转换回char
int i = reader.read();

// 连续读三次,可以读到三个字符,若第三个没值,则返回-1,可作为读取结束条件
reader.read()
reader.read()
reader.read()

read(char[] chars)是将数据读入到参数的数组中,返回的是读取到数据的长度

reader = new FileReader(file);
char[] cs = new char[5];
int i = reader.read(cs);
// 若最后只读取到i=2个数据,只会覆盖原数组的前两个数据,后面三个不变
// 当i = -1时候,说明没有读到数据了
i = reader.read(cs);
以追加的方式写入,而不是覆盖;换行怎么写

new FileWriter(“file.txt”,true)
\n代表换行,或\r\n

BufferedReader
reader = new BufferedReader(new FileReader(file));
String line = reader.readLine();
// BufferedReader关闭,里面的FileReader也会关闭
reader.close();

if(line != null){
	//这个就是读取的边界
}
writer = new BufferedWriter(new FileWriter(file));
//写入一行
writer.write("abc");
// 要想换换必须加这个方法
writer.newLine();
writer.write("xyz");
writer.flush();
字节流FileOutputStream、FileInputStream 、BufferedInputStream、BufferedOutputStream
byte[] bytes = {123,34,45,34};
outputStream = new FileOutputStream(file);
outputStream.write(bytes);
// 字节流无需flush
outputStream.close()
byte[] bs = new byte[5];
FileInputStream inputStream = new FileInputStream(file);
// 读到多少个字节 i,当i为-1时,表示没有读到数据
int i = inputStream.read(bs);

// 指定解码格式,对字节进行解码
 String(@NotNull byte[] bytes,
              int offset,
              int length,
              @NotNull java.nio.Charset charset)
in = new BufferedInputStream(new FileInputStream(file));
out = new BufferedOutputStream(new FileOutputStream(file));

byte[] bs = new byte[1024];
// 当len为-1时候表示没读到数据
int len = in.read(bs)
out.write(bs,0,len)

InputStream转字节数组
byte[] readStream(final InputStream inputStream) {
	ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    byte[] data = new byte[INPUT_STREAM_DATA_CHUNK_SIZE];
    int bytesRead;
    while ((bytesRead = inputStream.read(data, 0, data.length)) != -1) {
      outputStream.write(data, 0, bytesRead);
    }
    outputStream.flush();
    return outputStream.toByteArray();
}
class ByteArrayOutputStream extends OutputStream {
	// 数据没有存在文件里,而是这个数组中
	byte buf[];
	public ByteArrayOutputStream() {
        this(32);
    }
    
    void write(byte b[], int off, int len) {
        if ((off < 0) || (off > b.length) || (len < 0) ||
            ((off + len) - b.length > 0)) {
            throw new IndexOutOfBoundsException();
        }
        ensureCapacity(count + len);
        // 复制数组
        System.arraycopy(b, off, buf, count, len);
        count += len;
    }
}
BufferedOutputStream源码
class BufferedOutputStream extends FilterOutputStream {
	byte buf[];
	
	public synchronized void write(byte b[], int off, int len) throws IOException {
        if (len >= buf.length) {
            flushBuffer();
            out.write(b, off, len);
            return;
        }
        // 将数据先放到buf缓存中
        System.arraycopy(b, off, buf, count, len);
        count += len;
    }

	private void flushBuffer() throws IOException {
        if (count > 0) {
            out.write(buf, 0, count);
            count = 0;
        }
    }
}
class FilterOutputStream extends OutputStream {
	OutputStream out;
	
	public void write(int b) throws IOException {
        out.write(b);
    }
}
字符流编码与字节流
OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(file), "gbk");
// 这个“中”字是以gbk形式存储,将来读取的时候也要以gbk取数据
writer.write("中");

char[] cs = new char[1024];
// 解码必须以jdb
InputStreamReader reader = new InputStreamReader(new FileInputStream(file), "GBK");
int len = reader.read(cs);
new String(cs,0,len);
打印流,只有writer,没有reader
// 将数据输出到文件file
PrintWriter writer = new PrintWriter(file);
writer.println("hello");
writer.print("world");
writer.flush();

// 将读到的数据打印到控制台
PrintWriter writer = new PrintWriter(System.out);
writer.flush();
Properties
// 线程安全,只能存字符串
Properties extends Hashtable<Object,Object> {
	public synchronized Object setProperty(String key, String value) {
        return put(key, value);
    }
}
Properties properties = new Properties();
properties.setProperty("001","张三");
properties.setProperty("002","李四");

String value = properties.getProperty("001");

// 将properties数据写到文件中
PrintWriter writer = new PrintWriter(file);
properties.list(writer);
writer.flush();
// 从文件中加载到properties里
Properties properties = new Properties();
FileInputStream inputStream = new FileInputStream(file);
properties.load(inputStream);
序列化流
// Person要实现序列化接口,加一个序列化id,不加序列化id,当类变化例如增加字段时,反序列化会报错

ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(file));
outputStream.writeObject(new Person());
outputStream.flush();

ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(file));
Object o = inputStream.readObject();

// 一般使用集合,集合实现了序列化接口
list.add(person1)
list.add(person2)
outputStream.writeObject(list);
标签接口
  • 标签接口没有任何方法和属性
  • 主要有两个用途,第一:标识同一类型的类,如org.aopalliance.aop.Advice;第二:使程序或JVM采取一些特殊处理,如io.Serializable

File

  1. File:
file.exists()
file.createNewFile()
file.mkdir()
//创建多级目录
file.mkdirs()
//删除不走回收站,删除文件和目录最后一层
file.delete()
//获取文件绝对路径
file.getAbsolutePath()
//new File("b.txt"),相对路径是相对项目名作为根路径
//获取相对路径
file.getPath()
file.getName()
//文件大小,多少字节
file.length()
File[] files = file.listFiles();
boolean canExecute = file.canExecute();
boolean canRead = file.canRead();
boolean canWrite = file.canWrite();
boolean hidden = file.isHidden();

//体现层级关系递归打印目录树,注意space的使用
int space = 1;
void print(File file) {
	space ++;
    File[] files = file.listFiles();
    for (File f : files) {
        printSpace(space);

        System.out.println(f);

        if (f.isDirectory()) {
            printFile(file);
        }
    }
    space --;
}


// 递归删除目录下的所有文件和目录,注意,只能删除空目录
void deleteDirector(File file) {
	   if (file == null || !file.exists()) {
	       return;
	   }
	
	   File[] files = file.listFiles();
	   for (File f : files) {
	       if (f.isDirectory()) {
	           deleteDirector(f);
	       }else {
	           f.delete();
	       }
	   }
	   //这步是点睛之笔
	   file.delete();
}

nio之Paths、Files使用
Path path= Paths.get(new URI(myPath));
byte[] cLassBytes= Files.readAllBytes(path);

反射

每个类编译之后都会有一个class文件,什么时候加载到JVM中的,static{//代码块}这里面的代码块什么时候被执行

对其第一次使用时:

new Dog();
Class<?> clazz = Class.forName("com.file.Dog");
Dog.staticAttribute
Dog.staticMethod
类加载器的意义

任意一个类,都需要由加载它的类加载器和这个类本身一同确定其在java虚拟机中的唯一性

双亲委派模型的好处

Java类随着它的类加载器具备了一种带有优先级的层次关系。例如Object放在rt.jar中,无论哪一个类加载器加载这个类,最终都是委派给模型最顶端的启动类加载器加载

ClassLoader的使用与getDefaultClassLoader源码
  • 双亲委派模型
    启动类加载器(bootstrap classloader):负责JAVA_HOME/lib目录
    扩展类加载器(extension classloader):JAVA_HOME/lib/ext目录
    应用程序类加载器(application classloader):也叫系统类加载器,负责类路径
// 应用程序类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
Class<?> loadClass(String name) {
	// 检查是否已被加载过
	Class<?> c = findLoadedClass(name);
    if (c == null) {
        try {
            if (parent != null) {
                c = parent.loadClass(name, false);
            } else {
            	// Returns a class loaded by the bootstrap class loader;
                c = findBootstrapClassOrNull(name);
            }
        } catch (ClassNotFoundException e) {
            // ClassNotFoundException thrown if class not found
            // from the non-null parent class loader
            // 这里并没有打印异常
        }

        if (c == null) {
            // If still not found, then invoke findClass in order
            // to find the class.
            c = findClass(name);
        }
    }
	return c;
}
InputStream inputStream = Test.class.getClassLoader().getResourceAsStream("spring-config.xml");
  • 自定义类加载器,加载class文件的字节流
还没找到答案
class ClassUtils {
	static ClassLoader getDefaultClassLoader() {
		ClassLoader cl = null;
		try {
			// 方式一获得ClassLoader 
			cl = Thread.currentThread().getContextClassLoader();
		}
		if (cl == null) {
			// 方式二
			cl = ClassUtils.class.getClassLoader();
			if (cl == null) {	
				// 方式三
				cl = ClassLoader.getSystemClassLoader();				
			}
		}
	}
}

获得Class的几种途径,基本数据类型例如int有class属性吗

Class<?> clazz = Class.forName("com.file.Dog");

Object object = new Object();
Class<?> clazz = object.getClass();

Class<Dog> clazz = Dog.class;

Class<Integer> integerClass = int.class;
Class<Integer> integerClass1 = Integer.TYPE;

ClassLoader defaultClassLoader = ClassUtils.getDefaultClassLoader();
Class<?> clazz = defaultClassLoader.loadClass("com.file.Dog");

通过反射创建类对象

Class<Dog> dogClass = Dog.class;
Dog dog = dogClass.newInstance();
Constructor<Dog> constructor1 = dogClass.getConstructor();
Constructor<Dog> constructor2 = dogClass.getConstructor(String.class);
Dog dog1 = constructor1.newInstance();
Dog dog2 = constructor2.newInstance("小黄");

instanceof 与 isInstance与isAssignableFrom区别

Dog dog = new Dog();
boolean b = dog instanceof Dog;
boolean b1 = Dog.class.isInstance(dog);
// 虽然Animal是Dog的父类,但是类型不完全一致,返回false
boolean b2 = Dog.class.isAssignableFrom(Animal.class);

getFields()与getDeclaredFields()区别

Class<Dog> dogClass = Dog.class;
// 只能获得public属性
Field[] fields = dogClass.getFields();
// 不仅可以获得public,还可以获得private等所有属性,但不包括父类属性
Field[] declaredFields = dogClass.getDeclaredFields();

获取指定公有字段和私有字段,并使用

Dog dog = new Dog();
Class<? extends Dog> dogClass = dog.getClass();
Field dogName = dogClass.getDeclaredField("dogName");
// 必须设置为true,否则私有没权限访问
dogName.setAccessible(true);
dogName.set(dog,"小黄");
Object nameString = dogName.get(dog);

获取类的方法,并使用,普通方法和静态方法

  • 普通方法
// 获得类的指定public方法
// 获取所有public修饰的方法:getMethods
// 获得所有方法,包括private,getDeclaredMethods
Method say = dogClass.getMethod("say", String.class);
Object returnValue = say.invoke(dog, "汪汪汪");
  • 静态方法
Method mainMethod = Class.forName("com.Test")
        .getMethod("main", String[].class);
// 注意invoke的第一个参数为空,因为没有创建对象
mainMethod.invoke(null, (Object)new String[]{"111", "222", "333"});

获得类上的注解,Method,Field

Class<BookService> bookService2Class = BookService.class;
Annotation[] annotations = bookServiceClass.getAnnotations();
for (Annotation annotation : annotations) {
    if (annotation instanceof Scope) {
        Scope annotation = (Scope) annotation;
        String value = ((Scope) annotation).scopeName();
        System.out.println(value);
    }
}
final class Class<T> implements AnnotatedElement {
	public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
        Objects.requireNonNull(annotationClass);

        return (A) annotationData().annotations.get(annotationClass);
    }
}
final class Method extends Executable {
}

abstract class Executable extends AccessibleObject implements Member {
}

class AccessibleObject implements AnnotatedElement {
}
final class Field extends AccessibleObject implements Member {}

可以获取继承来的属性和方法吗

  • getSuperclass
Class<?> animalClazz = dogClass.getSuperclass();
Object animal = animalClazz.newInstance();
Field[] fields = animalClazz.getDeclaredFields();
fields[0].setAccessible(true);
Object age = fields[0].get(animal);
System.out.println(age);

Class的getName、getSuperclass、getInterfaces、isInterface、getSimpleName三个方法的含义

// "com.Dog"
String name = dogClass.getName();
Class<?> superclass = dogClass.getSuperclass();
Class<?>[] interfaces = dogClass.getInterfaces();
boolean b = dogClass.isInterface();
// "Dog"
String simpleName = dogClass.getSimpleName();

java-Type

// 所有数据类型都继承自Type,Class就是继承自Type的
Type type = TypeTest.class;

// 下面演示获得<Integer>
Foo<Integer> foo = new Foo<Integer>(){};
// com.fanxin.Foo<java.lang.Integer>
Type mySuperClass = foo.getClass().getGenericSuperclass();
// type = class java.lang.Integer
Type type = ((ParameterizedType)mySuperClass).getActualTypeArguments()[0];
public class TypeVariableTest<T extends Number & Serializable> {
    private T t;
}


Field fieldT = TypeVariableTest.class.getDeclaredField("t");
// T
TypeVariable typeVariable=(TypeVariable)fieldT.getGenericType();

Type[] types=typeVariable.getBounds();

for (Type type:types){
	// class java.lang.Number
	// interface java.io.Serializable
    System.out.println(type);
}
// T
System.out.println(typeVariable.getName());
// class com.fanxin.TypeVariableTest
GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
public class WildcardTypeTest {

    private List<? extends String> listStr;

    private List<? super String> b;

    public static void testGetBounds(String field) throws NoSuchFieldException {

        Field f = WildcardTypeTest.class.getDeclaredField(field);
        // java.util.List<? extends java.lang.String>
        Type type = f.getGenericType();
        ParameterizedType parameterizedType = (ParameterizedType)type;
        Type[] types = parameterizedType.getActualTypeArguments();

        WildcardType wildcardType = (WildcardType) types[0];
        {
            Type[] types = wildcardType.getUpperBounds();
            for (Type type : types) {
                System.out.println(type);
            }

            types = wildcardType.getLowerBounds();
            for (Type type : types) {
                System.out.println(type);
            }
        }

    }

    public static void testGetUpperBounds() throws  NoSuchFieldException
    {
    	//listStr
		//class java.lang.String
        testGetBounds("listStr");
        
        // b
		// class java.lang.Object
		// class java.lang.String
        testGetBounds("b");
    }

    public static void main(String[] args) throws NoSuchFieldException {
        testGetUpperBounds();
    }
}
public class GenericArrayTypeBean<T> {
    // 属于 GenericArrayType
    List<String>[] pTypeArray;
    // 属于 GenericArrayType
    T[] vTypeArray;
    // 不属于 GenericArrayType
    List<String> list;
    // 不属于 GenericArrayType
    String[] strings;

    public static void main(String[] args) throws NoSuchFieldException {
        Field field = GenericArrayTypeBean.class.getDeclaredField("pTypeArray");
        // java.util.List<java.lang.String>[]
        GenericArrayType genericType = (GenericArrayType)field.getGenericType();
        // java.util.List<java.lang.String>
        Type genericComponentType = genericType.getGenericComponentType();
    }
}
  • getSuperclass、getGenericSuperclass区别
public class TypeTest {

    class Person<T> {
    }

    class Student extends Person<TypeTest> {
    }

    public static void main(String[] args) {
        new TypeTest().test();
    }

    public void test() {
        System.out.println("Student.class.getSuperclass()\t"
                + Student.class.getSuperclass());
        System.out.println("Student.class.getGenericSuperclass()\t"
                + Student.class.getGenericSuperclass());
        System.out.println();

        System.out.println("TypeTest.class.getSuperclass()\t"
                + TypeTest.class.getSuperclass());
        System.out.println("TypeTest.class.getGenericSuperclass()\t"
                + TypeTest.class.getGenericSuperclass());
        System.out.println();

        System.out.println("Object.class.getGenericSuperclass()\t"
                + Object.class.getGenericSuperclass());
        System.out.println("Object.class.getSuperclass()\t"
                + Object.class.getSuperclass());
        System.out.println();

        System.out.println("void.class.getSuperclass()\t"
                + void.class.getSuperclass());
        System.out.println("void.class.getGenericSuperclass()\t"
                + void.class.getGenericSuperclass());
        System.out.println();

        System.out.println("int[].class.getSuperclass()\t"
                + int[].class.getSuperclass());
        System.out.println("int[].class.getGenericSuperclass()\t"
                + int[].class.getGenericSuperclass());
    	
    	// Student.class.getSuperclass()	class com.fanxin.TypeTest$Person
		// Student.class.getGenericSuperclass()	com.fanxin.TypeTest.com.fanxin.TypeTest$Person<com.fanxin.TypeTest>

		//TypeTest.class.getSuperclass()	class java.lang.Object
		//TypeTest.class.getGenericSuperclass()	class java.lang.Object

		//Object.class.getGenericSuperclass()	null
		//Object.class.getSuperclass()	null

		//void.class.getSuperclass()	null
		//void.class.getGenericSuperclass()	null

		//int[].class.getSuperclass()	class java.lang.Object
		//int[].class.getGenericSuperclass()	class java.lang.Object
    }
}
  • field.getType与getGenericType区别
public class FieldTest {


    class Person<T> {

        public List<CharSequence> charSequenceList;

        public String str;
    }

    class Student extends Person<FieldTest> {


    }

    public static void main(String[] args) throws NoSuchFieldException {
        new FieldTest().test1();
    }

    public void test1() throws NoSuchFieldException {

        {
            Field field=Student.class.getField("str");
            // class java.lang.String
            // class java.lang.String
            System.out.println(field.getType());
            System.out.println(field.getGenericType());
        }

        {
            Field field=Student.class.getField("charSequenceList");
            // interface java.util.List
            // java.util.List<java.lang.CharSequence>
            System.out.println(field.getType());
            System.out.println(field.getGenericType());
        }
    }
}
  • Method # getParameterTypes、getGenericParameterTypes
public class MethodTest {


    static class Person<T> {

    }

    static class Student extends Person<MethodTest> {


        public Student(List<CharSequence> list)
        {

        }

        public Integer test(List<CharSequence> list)
        {
            return null;
        }

    }

    public static void main(String[] args) throws NoSuchMethodException {
        new MethodTest().test1();
    }
    public void test1() throws NoSuchMethodException {

        {
            Method method=Student.class.getMethod("test",List.class);
            // interface java.util.List
            Class type1=method.getParameterTypes()[0];
            // java.util.List<java.lang.CharSequence>
            Type type2=method.getGenericParameterTypes()[0];           
        }

        {
            Constructor constructor=Student.class.getConstructor(List.class);
			// interface java.util.List
            Class type1=constructor.getParameterTypes()[0];
            // java.util.List<java.lang.CharSequence>
            Type type2=constructor.getGenericParameterTypes()[0];            
        }
    }
}
  • spring的MethodParameter
public class MethodParameterTests {

    public static class TestItem
    {
        public TestItem(List<String> list)
        {

        }

        public void m1(List<Integer> intParam)
        {

        }
    }

    public static void main(String[] args) throws NoSuchMethodException {
        new MethodParameterTests().test();
    }
    public void test() throws NoSuchMethodException {

        {
            Method method=TestItem.class.getMethod("m1",List.class);
            // method 'm1' parameter 0
            MethodParameter parameter=MethodParameter.forMethodOrConstructor(method,0);
            // interface java.util.List
			Class<?> parameterType = parameter.getParameterType();
			// java.util.List<java.lang.Integer>
            Type genericParameterType = parameter.getGenericParameterType();
        }

        {
            Constructor constructor=TestItem.class.getConstructor(List.class);
            MethodParameter parameter=MethodParameter.forMethodOrConstructor(constructor,0);
            // interface java.util.List
            Class<?> parameterType = parameter.getParameterType();
            // java.util.List<java.lang.String>
            Type genericParameterType = parameter.getGenericParameterType();
        }
    }
}

ResolvableType

public class Test {
    static class ExtendsList extends ArrayList<CharSequence> {
        public List charSequenceList;
        public String[] arrayType;

        // 属于 GenericArrayType
        List<String>[] pTypeArray;

        public String charSequenceParameter(List<String> list,String s){
            return "";
        }
    }

    public static void main(String[] args) throws Exception {
        {
            ResolvableType extendsListResolvableType = ResolvableType.forClass(ExtendsList.class);
            // class com.fanxin.Test$ExtendsList
            Type type = extendsListResolvableType.getType();
            // class com.fanxin.Test$ExtendsList
            Class<ExtendsList> extendsListClass = ExtendsList.class;
            // class com.fanxin.Test$ExtendsList
            Type t = extendsListClass;
        }

        {
            Field charSequenceList = ExtendsList.class.getField("charSequenceList");
            ResolvableType fieldResolvableType = ResolvableType.forField(charSequenceList);
            // interface java.util.List
            Type type = fieldResolvableType.getType();
            // interface java.util.List
            Type fieldGenericType = charSequenceList.getGenericType();
        }

        {
            Method method = ExtendsList.class.getMethod("charSequenceParameter", List.class,String.class);
            // 封装方法的第一个参数
            MethodParameter methodParameter = MethodParameter.forMethodOrConstructor(method, 0);
            ResolvableType resolvableType = ResolvableType.forMethodParameter(methodParameter);
            // java.util.List<java.lang.String>
            Type type = resolvableType.getType();
            // class java.lang.String
            Type genericParameterType = method.getGenericParameterTypes()[1];
            // java.util.List<java.lang.String>
            Type genericParameterType1 = method.getGenericParameterTypes()[0];
        }

        {
            ResolvableType extendsListResolvableType = ResolvableType.forClass(ExtendsList.class);
            // class com.fanxin.Test$ExtendsList
            Class<?> rawClass = extendsListResolvableType.getRawClass();
        }

        {
            ResolvableType extendsListResolvableType = ResolvableType.forClass(ExtendsList.class);
            ResolvableType superType = extendsListResolvableType.getSuperType();
            // java.util.ArrayList<java.lang.CharSequence>
            Type type = superType.getType();
            // class java.util.ArrayList
            Class<?> rawClass = superType.getRawClass();
        }

        {
            ResolvableType extendsListResolvableType = ResolvableType.forClass(ExtendsList.class);
            // as向上取接口或父类
            ResolvableType resolvableType = extendsListResolvableType.as(ArrayList.class);
            // java.util.ArrayList<java.lang.CharSequence>
            Type type = resolvableType.getType();
            // class java.util.ArrayList
            Class<?> rawClass1 = resolvableType.getRawClass();
            // class java.util.ArrayList
            ResolvableType generic = resolvableType.getGeneric();
            // interface java.lang.CharSequence
            Type type3 = resolvableType.getGeneric().getType();
            // interface java.lang.CharSequence
            Class<?>[] classes = resolvableType.resolveGenerics();
        }

        {
            Field arrayType = ExtendsList.class.getField("arrayType");
            ResolvableType resolvableType = ResolvableType.forField(arrayType);
            // true
            boolean b = resolvableType.isArray();
            // java.lang.String
            ResolvableType componentType = resolvableType.getComponentType();
            // class java.lang.String
            Type type = resolvableType.getComponentType().getType();
            // class java.lang.String
            Type componentType = ((Class) arrayType.getGenericType()).getComponentType();

            Type type1 = resolvableType.getType();
            // ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.GenericArrayType
            // String[] 不属于GenericArrayType
            // List<String>[]属于
            GenericArrayType type11 = (GenericArrayType) type1;
        }
    }
}

java动态代理

  • 要实现动态代理,首先准备一个被代理的对象和被代理对象的接口,代理的就是接口中的方法
public interface InterfaceMy {
    void doSomething();
    void somethingElse(String arg);
}


public class RealObj implements InterfaceMy {
    @Override
    public void doSomething() {
        System.out.println("doSomething");
    }

    @Override
    public void somethingElse(String arg) {
        System.out.println("somethingElse" + arg);
    }
}
public class DynamicProxyHandler implements InvocationHandler {

    private Interface proxied;

    public DynamicProxyHandler(Interface proxied) {
        this.proxied = proxied;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("收保护费");
        // method.invoke 是调用对象本身方法
        return method.invoke(proxied,args);
    }
}
RealObj realObj = new RealObj();
Interface i =(Interface) Proxy.newProxyInstance(
        Interface.class.getClassLoader(),
        new Class[]{Interface.class},
        new DynamicProxyHandler(realObj)
);

i.doSomething();

注意需要参数:
class数组,因为realobj可能实现多个接口,获得所有接口则realobj.getClass().getInterfaces()

动态代理实现数据库事务

ConnectionManager.benigTransction(conn);
param = method.invoke(obj, args);
// 提交事务
ConnectionManager.endTransction(conn);
return param;

注解

元注解Target、Retention作用

  • Target:定义你的注解将应用于什么地方,域还是方法,例:@Target({ElementType.METHOD,ElementType.TYPE})
  • Retention:注解在哪一个级别可用,源代码、类文件或运行时@Retention(RetentionPolicy.RUNTIME)

怎么定义注解,怎么定义注解处理器

  • 注解定义:元注解、@interface、元素。@interface定义注解,interface定义接口;元素与接口方法区别是元素可以设置默认值,元素里面没有参数,元素的值就是元素的返回值,例如id=56,description=“hello”
public int id();
public String description() default "no description";
  • 注解处理器:class.getDeclaredMethods,method.getAnnotation(注解.class),annotation.id()、annotation.description()。getAnnotation属于AnnotatedElement的方法,Class、Method、Field都实现了这个接口
  • 没有元素的注解是标记注解

元素命名为value有什么讲究

使用时,不需要value = “xxx”,直接用就是了

注解元素可用的类型

  • String、Class、Annotation、Class,和以上类型数组
  • 切记,不允许使用任何包装类型

注解与接口区别

注解+动态代理实现事务

阿里巴巴java开发规范

命名方面知道哪些

驼峰、常量大写下划线隔开、抽象类以abstract或base开头、异常类以exception结尾、测试类要以测试的类名开头,以Test结尾、

POJO的Boolean类型变量命名为什么不要加is

部分框架解析会引起序列化错误。
基本数据类型 Boolean isDeleted 的属性,它的方法也是 isDeleted(),RPC框架在反向解析的时候,“误以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异常

包名规范要注意()

使用小写、使用单数

缩写要注意()

缩写之后连意思都找不到了要避免

接口类中的方法和属性要加修饰符吗,例如public

不要

接口与实现类命名()

Impl

获取单个对象的方法使用()做前缀,多个对象(),统计值(),插入(),删除(),修改()

get、list、count、save/insert、remove/delete、update

领域模型包括()()()

数据对象、数据传输对象、展示对象

什么是数据对象,什么是展示对象,命名规范是什么

数据对象:xxxDO,xxx为数据表名
展示对象:xxxVO,xxx为网页名
数据传输对象:xxxDTO,xxx为业务领域相关的名称

为什么不能使用xxxPOJO命名

pojo是DO、DTO、VO的总称

什么是魔法值

未经预定义的常量,要避免

Long类型的值要注意()

后面不能是小l,应该是大L

所有常量放在一个常量类中可以吗

不可以,应该分类

常量复用有五层,类、包、()()()

子工程内,应用内、跨应用

易懂变量要定义在五层中的哪一层

应用内

大括号强制()

左大括号前不换行,后换行

左小括号与字符间()

不出现空格

保留字与括号之间()

必须加空格

运算符的左右需要加()

空格,例如 a == b a = b

注释的斜线与注释的内容()

必须加空格

单行字符超过120个,需换行,换行需注意运算符(),一二行(),

运算符与上下文一起换行,第二行相对第一行缩进四个空格

调用方法时,多个参数需要()

逗号后面必须空格

如何使单个方法总行数不超过80

代码逻辑分清红花和绿叶,个性和共性
绿叶逻辑单独出来成为额外方法,共性逻辑抽取成为共性方法

访问类的静态变量或方法要避免()

使用对象点. ,直接使用类名点

可变参数编程提倡吗

不提倡

equals的左右注意

左边最好是常量和确定值

包装类型之间值的比较,使用equals还是==

使用equals

pojo属性使用基本类型还是包装类型

包装类型

局部变量使用基本类型还是包装类型

基本类型

返回值和参数使用基本类型还是包装类型

包装类型

pojo类属性默认值可以设置吗

不可以

构造方法内需要业务逻辑怎么办

构造方法不要加任何业务逻辑,可以放在init中

pojo类必须写()方法,方便测试

tostring()

类内方法定义的顺序依次是

公有方法或保护方法 > 私有方法 > getter/setter 方法

循环体内拼接字符串使用string还是stringbuilder

使用stringbuilder,因为string会每次循环都出来一个stringbuilder对象,造成内存浪费

重写equals方法时,要注意

同时重写hashcode

为什么我们经常使用string来作为map的key

因为string重写了hashcode和equals方法

ArrayList为什么不可强转为subList

sublist只是其一个视图,是arraylist的内部类,

集合转数组toarray要注意什么

list.toArray(array),传入array大小为list.size()

foreach时候删除怎么办

不能直接删除集合里的元素,必须iterator.remove

实现comparable接口时,要注意()

处理相等时候的情况

遍历map应该使用哪种方式

不要使用keyset,因为遍历了两次
使用entryset
jdk8:

// 传统的Map迭代方式
for (Map.Entry<String, Object> entry : infoMap.entrySet()) {
    System.out.println(entry.getKey() + ":" + entry.getValue());
}
// JDK8的迭代方式
infoMap.forEach((key, value) -> {
    System.out.println(key + ":" + value);
});

讨论hashmap、treemap、ConcurrentHashMap 、hashtable的空值与线程安全

除了hashmap允许key为空,其他都不行,hashmap和treemap允许value为空,hashtable和concurrenthashmap不允许value为空,hashtable线程安全,concurrenthashmap部分安全,剩下两个不安全

怎么理解集合的有序和稳定,哪些是有序,哪些是稳定

arraylist是稳定,无序
treeset是有序,稳定
hashmap是无序,不稳定

线程池与显示创建线程注意什么

不允许显示创建线程

线程池创建要注意

线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式

为什么不能使用executor创建线程池

Executors创建的线程池存在OOM的风险,使用了linkedblockqueue,LinkedBlockingQueue是一个用链表实现的有界阻塞队列,容量可以选择进行设置,不设置的话,将是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE

怎么正确创建线程池

private static ExecutorService executor = new ThreadPoolExecutor	
		(10, 10,
        60L, TimeUnit.SECONDS,
        new ArrayBlockingQueue(10));

TimeUnit类型:将一天转为24小时,一小时有多少秒,3天转为小时

System.out.println( TimeUnit.DAYS.toHours( 1 ) );
System.out.println( TimeUnit.HOURS.toSeconds( 1 ));
System.out.println( TimeUnit.HOURS.convert( 3 , TimeUnit.DAYS ) );

timeunit进行延时怎么做

TimeUnit.SECONDS.sleep( 5 );

相当于

Thread.sleep( 5 * 1000 );

SimpleDateFormat 是线程不安全的类怎么解决安全问题

private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {        
		@Override        
		protected DateFormat initialValue() {            
			return new SimpleDateFormat("yyyy-MM-dd");       
		}    
}; 

Date、Calendar、SimpleDateFormate在jdk1.8可被哪些替代

Date:Instant
LocalDateTime:Calendar
DateTimeFormatter:SimpleDateFormate
官方解释:简单,漂亮,强壮,不变,线程安全

对象锁与类锁哪些对性能更好

对象锁更好

对多个资源,数据表,对象加锁时需要()

保持一致的加锁顺序

并发修改同一记录时,避免更新丢失,加锁方式:应用层加锁,(),()

缓存加锁,数据库加锁

什么时候用乐观锁,什么时候用悲观锁

如果每次访问冲突概率小于 20%,推荐使用乐观锁,否则使用悲观锁。乐观锁的重试次 数不得小于 3 次

定时任务timer使用()代替

ScheduledExecutorService
多线程并行处理定时任务时,Timer 运行多个 TimeTask 时,只要其中之一没有捕获 抛出的异常,其它任务便会自动终止运行,使用 ScheduledExecutorService 则没有这个问题。

使用 CountDownLatch 进行异步转同步操作,每个线程退出前必须调用 countDown 方法,线程执行代码注意 ()

catch 异常,确保 countDown 方法被执行到

子线程抛出的异常能否在主线程trycatch到()

不能

异常被捕获了,事务还会回滚吗

不仅不会回滚,而且会继续往下执行

事务只能回滚()异常

runtimeexception,如果抛出exception事务不会回滚,因为spring捕获的是runtimeexception

一个类里面。a方法调用b方法,b方法调用c方法,只有c方法需要事务, 我应该把transaction注解加在哪个方法上面

a方法,只有加在调用链上的第一个方法才有效,c方法不需要加transaction,但是a,b,c三个方法必须都是public方法

有 try 块放到了事务代码中,catch 异常后,如何回滚事务

手动回滚事务

spring事务传递

外围方法未开启事务的情况下Propagation.REQUIRED修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰,举例理解

a方法调用b、c方法,后抛出runtimeexception,并不会影响b,c方法自己事务,且b,c自己事务是独立的

外围方法a有事务,调用b,c方法后外围方法a抛出runtimeexception,b、c都开启了自己的事务(Propagation.REQUIRED),问:b、c会回滚自己的事务吗

会,b,c加入外围事务

外围方法a,内部方法b,c都开启事务,b抛出runtimeexception,只会回滚b方法吗

不是,a连带c都会回滚

外围方法a,内部方法b,c都开启事务REQUIRED,在a中trycatch调用b代码块的异常,还会回滚吗

依然回滚,外围方法开启事务的情况下Propagation.REQUIRED修饰的内部方法会加入到外围方法的事务中,所有Propagation.REQUIRED修饰的内部方法和外围方法均属于同一事务,只要一个方法回滚,整个事务均回滚

将上述b、c方法上改为Propagation.REQUIRES_NEW,a方法也开启事务会怎么样

b,c不会加入a的事务,a抛异常不会导致b,c回滚

c是REQUIRES_NEW,a是REQUIRED,c的异常会导致a回滚吗

会,c抛出异常回滚,异常继续抛出被外围a感知,a也回滚
所有以REQUIRED加入a的都会回滚

b以REQUIRES_NEW和以REQUIRED抛出异常,在a处捕获,会导致a的事务回滚吗

REQUIRED即使在外围捕获异常,依然会回滚
REQUIRES_NEW被捕获了就不会导致外围事务回滚

runtimeException一般不用捕获,但是我捕获之后事务还会回滚吗

由于异常被捕获了,spring感知不到异常,所以不会回滚,例外就是;b事务是REQUIRED,外围事务a方法里面捕获b,依然会导致a和b两个事务回滚

Propagation.NESTED,修饰的内部方法属于外部事务的子事务,外围主事务回滚,子事务一定回滚,而内部子事务可以单独回滚而不影响外围主事务和其他子事务。举例论证

b抛出异常,a感知到b的异常,导致a,b,c都回滚,这点像REQUIRED
b抛出异常,外围a捕获异常,那么a,c不会回滚,这点像REQUIRES_NEW

NESTED与REQUIRES_NEW区别

外围抛出异常,NESTED会回滚,而REQUIRES_NEW不会

Random的问题,以及替代方案

多线程中性能不高,使用ThreadLocalRandom代替
多线程使用threadlocalrandom需要在每个线程ThreadLocalRandom.current().nextInt(100)

volatile 解决多线程内存不可见问题,对于()是可以解决变量同步问题,但是对于()同样无法解决线程安全问题,对于count++操作,推荐使用()

一写多读
多写
LongAdder

ThreadLocal 对象建议使用 ()修饰

static

使用switch,必须()()

每个case使用return或break终止,必须最后包含一个default语句放到最后

在 if/else/for/while/do 语句中必须使用()。即使只有一行代码,

大括号

在高并发场景中,避免使用()判断作为中断或退出的条件。

”等于”
容易产生等值判断被“击穿”的情况,使用大于或小于的区间 判断条件来代替

超过 3 层的 if-else 的逻辑判断代码可以使用()()()

卫语句、策略模式、状态模式

不要在条件判断中执行()

复杂语句

final boolean existed = (file.open(fileName, "w") != null) && (...) || (...); 
if (existed) {     ... }   

哪些地方不需要做参数校验

dao层不需要,都到最下层了,不太可能出问题

注释必须()

/*内容/,不要//

注释所有的类都必须添加()()

创建者和创建日期

使用正则表达式注意

预编译不要放在方法体内
不要在方法体内定义:Pattern pattern = Pattern.compile(“规则”);

获取当前毫秒数 建议使用()

System.currentTimeMillis(); 而不是 new Date().getTime();

循环里没有trycatch异常,抛出异常会终止程序吗

为什么不要在 finally 块中使用 return

finally 块中的 return 返回后方法结束执行,不会再执行 try 块中的 return 语句

日志不能直接使用(),而应依赖()

(Log4j、Logback)中的 API
而应依赖使用日志框架 SLF4J 中的 API

import org.slf4j.Logger;  
import org.slf4j.LoggerFactory; 
 
private static final Logger logger = LoggerFactory.getLogger(Abc.class); 

日志文件至少保存()天

15

日志文件的命名方式

APPname_logType_logname.log

为什么输出日志要加条件判断 if (logger.isDebugEnabled())

如果日志级别是 warn,上述日志不会打印,但是会执行里面的操作浪费了系统资源

举例占位符打印日志

logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol); 

遇到过重复打印日志的情况吗,怎么解决

LOG.info("info");
LOG.warn("warn");
LOG.error("error");

出现:

/home/info.log文件中会打印info,warn,error三行日志; 
/home/warn.log文件中会打印warn,error两行; 
/home/error.log文件中只会打印error一行日志。

解决:设置 additivity=false

日志记录异常信息应该包括()和()

案发现场信息和异常堆栈信息

logger.error(各类参数或者对象 toString() + "_" + e.getMessage(), e); 

日志级别排序

error、warn、info、debug

生产环境禁止输出()日志

debug

编码时隶属用户个人的页面或功能必须()

进行权限控制校验

用户敏感数据展示必须()

脱敏

什么是SQL注入

select where id = ?
用户输入 1 or 1=1,结果变成
id = 1 or 1=1

为什么mybatis的$不能防止SQL注入,而#可以防止大部分

#传入的数据会自动加一个双引号,$是直接拼接

mybatis怎么防止SQL注入

这是因为MyBatis启用了预编译功能,在SQL执行前,会先将上面的SQL发送给数据库进行编译;执行时,直接使用编译好的SQL,替换占位符“?”就可以了。因为SQL注入只能对编译过程起作用,所以这样的方式就很好地避免了SQL注入的问题

用户输入的参数必须()

进行有效性认证

跨域问题

CSRF攻击,以及解决方式

假如博客园有个加关注的GET接口,blogUserGuid参数很明显是关注人Id,如下:
https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=http%3A%2F%2Fwww.cnblogs.com%2Fmvc%2FFollow%2FFollowBlogger.aspx%3FblogUserGuid%3D4e8c33d0-77fe-df11-ac81-842b2b196315&pos_id=img-f52wGbIN-1725784270808)
那我只需要在我的一篇博文内容里面写一个img标签:

那么只要有人打开我这篇博文,那就会自动关注我
解决:服务端生成一个Token,用户请求时候必须携带token

在使用平台资源,譬如短信、邮件、电话、下单、支付,必须实现正确的防()

重放
发送验证码到手机,如果没有限制次数和频率,那么可以利用此功能骚扰到其 它用户,并造成短信平台资源浪费

MySQL数据库建表,Boolean类型的字段命名(),数据类型()

命名:is_xxx
数据类型:unsigned tinyint

数据库表名,字段名可以使用大写吗,表名要不要使用复数

不能
不需要,xxxDO也是单数,包名也不使用复数

主键索引命名,唯一索引命名,普通索引命名

pk_字段名
uk_字段名
idx_字段名

小数类型必须使用()

decimal

如果存储的字符串长度几乎相等使用()类型

char类型

表必备三字段

id,gmt_create,gmt_modified

哪种字段可以考虑冗余

字段长度短,不是频繁修改

什么时候可以考虑分库分表

单表行数超过 500 万行或者单表容量超过 2GB

业务上唯一特性的字段或多个字段组合强制()

建立唯一索引

建立索引必须制定(),没必要对全字段建立索引

索引长度

如果有order by,索引怎么建

order by 字段作为索引的一部分,但是放在最后面

count(*)与count(列名)区别

count*会统计值为null的行,count列名不会

统计不重复的行数

count(distinct col) 计算该列除 NULL 之外的不重复行数

count(distinct col1, col2) 如果其中一列全为 NULL,另一列有不同的值会返回()

0

当某一列的值全是 NULL 时,count(col)的返回结果为 (),但 sum(col)的返回结果为 ()

0
null

使用 ()来判断是否为 NULL 值。

isnull()
因为NULL 与任何值的直接比较都为 NULL

分页时遇到count为0时,应该()

直接返回,避免执行后面的分页语句

不得使用外键或级联,怎么办

在应用层解决

为什么禁止使用存储过程

存储过程难以调试和扩展,更没有移植性

数据的update和delete时,要先()

select,确认无误后才能执行

pojo的Boolean不能加is,而数据库字段加is,所以要()

在resultmap中写明映射关系

更新数据表记录时,必须同时更新记录对应的 ()

gmt_modified

使用事务的地方需 要考虑各方面的回滚方案,包括()(搜索引擎回滚)()()

缓存回滚,消息补偿,统计修正

开放接口层、终端显示层、web层、service层、manager层、dao层、外部接口或第三方平台

开放接口层:可直接封装 Service 方法暴露成 RPC 接口;通过 Web 封装成 http 接口;进行 网关安全控制、流量控制等。
终端显示层:各个端的模板渲染并执行显示的层。当前主要是 velocity 渲染,JS 渲染, JSP 渲染,移动端展示等。
Web 层:主要是对访问控制进行转发,各类基本参数校验,或者不复用的业务简单处理等。
Service 层:相对具体的业务逻辑服务层。
Manager 层:通用业务处理层,它有如下特征: 1) 对第三方平台封装的层,预处理返回结果及转化异常信息; 2) 对 Service 层通用能力的下沉,如缓存方案、中间件通用处理; 3) 与 DAO 层交互,对多个 DAO 的组合复用。
DAO 层:数据访问层,与底层 MySQL、Oracle、Hbase 等进行数据交互。
外部接口或第三方平台:包括其它部门 RPC 开放接口,基础平台,其它公司的 HTTP 接口

dao层不需要打印日志,因为()

在 DAO 层,产生的异常类型有很多,无法用细粒度的异常进 行 catch,使用 catch(Exception e)方式,并 throw new DAOException(e),日志在 Manager/Service 层一定需要捕获并打印到日志文件中去

注意超过 2 个参数的查询封装使用()对象,禁止使用()来传输

Query
Map

groupid、artifactid、version格式

groupid:com.公司.业务线.业务线
artifactid:产品名-模块名
version:起始版本必须为1.0.0

高并发服务器建议调小 TCP 协议的 time_wait 超时时间,为什么

操作系统默认 240 秒后,才会关闭处于 time_wait 状态的连接,在高并发访问下,服 务器端会因为处于 time_wait 的连接数太多,可能无法建立新的连接,所以需要在服务器上 调小此等待值

在线上生产环境,JVM 的 Xms 和 Xmx 设置

一样大,避免在 GC 后调整堆 大小带来的压力

主流的 linux 服务器默认所支持最大 fd 数量为 1024,fd是什么,什么时候可以调大

主流操作系统的设计是将 TCP/UDP 连接采用与文件一样的方式去管理,即一个连接对 应于一个 fd,
当并发连接数很大时很容易因为 fd 不足而出现“open too many files”错误,导致新的连接无法建立。 建议将 linux 服务器所支持的最大句柄数调高数倍(与服务器的内存数量相关)。

这些图是什么,怎么用:用例图、状态图、时序图、类图、活动图

【强制】在需求分析阶段,如果与系统交互的 User 超过一类并且相关的 User Case 超过 5 个, 使用用例图来表达更加清晰的结构化需求。
【强制】如果某个业务对象的状态超过 3 个,使用状态图来表达并且明确状态变化的各个触发 条件。
说明:状态图的核心是对象状态,首先明确对象有多少种状态,然后明确两两状态之间是否存
在直接转换关系,再明确触发状态转换的条件是什么。
正例:淘宝订单状态有已下单、待付款、已付款、待发货、已发货、已收货等。比如已下单与
已收货这两种状态之间是不可能有直接转换关系的。

【强制】如果系统中某个功能的调用链路上的涉及对象超过 3 个,使用时序图来表达并且明确 各调用环节的输入与输出。
说明:时序图反映了一系列对象间的交互与协作关系,清晰立体地反映系统的调用纵深链路。

【强制】如果系统中模型类超过 5 个,并且存在复杂的依赖关系,使用类图来表达并且明确类
之间的关系。
说明:类图像建筑领域的施工图,如果搭平房,可能不需要,但如果建造蚂蚁 Z 空间大楼,肯
定需要详细的施工图。

【强制】如果系统中超过 2 个对象之间存在协作关系,并且需要表示复杂的处理流程,使用活
动图来表示。
说明:活动图是流程图的扩展,增加了能够体现协作关系的对象泳道,支持表示并发等。

用例图与参与者的关联关系、包含、扩展、泛化

关联:例如用户转账,用户是角色,转账是用例,角色用一个小人表示,用例用一个椭圆表示,角色一个箭头指向用例,
包含:是指两个用例之间的关系,例如查询包含打印回执,提款和转账都包含打印回执,那么查询可以使用一个虚线箭头指向回执,如果两个用例有大量一致的功能,可以将这些功能分解到一个用例中,使用包含关系。
角色也可以执行被包含的用例,例如:取消订单包含查询订单,那么角色当然既可以取消订单,也可以查询订单。如果一个用例功能太多,也可以使用包含
扩展:把新的行为插入到已有用例中的方法,只在特定的条件发生,扩展用例才会被执行,例如:VIP打折用例是订购货物用例的扩展用例,画法是扩展用例一个虚线箭头指向基础用例,与包含不同的是《extend》与《include》
泛化:类似于继承,例如:父用例是预定,子用例是电话预定和网上预定,任何父用例出现的地方子用例也可以出现,使用箭头加三角形,子用例指向父用例

状态图若存在不同维度,例如一个订单有支付维度、快递状态、订单开闭状态,怎么画

先画不同维度的状态图,再合并

时序图用来描述用例中的()

行为顺序

当执行一个用例时, 时序图中的每条消息对应了()

一个类操作或者引起转换的触发事件

时序图中()是时间轴,横轴代表(),生命线指(),消息指(),激活和钝化指()

纵轴是时间轴,时间越向下越大
对象放在横轴顶部
生命线是一条垂直的虚线
消息是;两个对象之间的通信,发送方指向接收方
激活指生命线被占用以完成某个任务,钝化指生命线处于空闲状态
对象激活时将对象的生命线拓宽为矩形来表示的

泛型

Class的泛型
public <T> T getBean(String name, Class<T> requiredType)
Class<BookService> bookServiceClass = BookService.class;
泛型类和泛型方法的区别,泛型类和泛型接口的区别
  • 代码写法不同:
// 类
class Test<T> {
}

// 方法
public <T> T getBean(String name, Class<T> requiredType)
  • 泛型方法可以取代整个类,应该只使用泛型方法
  • static类和方法要想拥有泛型能力,必须使其成为泛型方法
  • 使用泛型类时,创建对象必须指定参数的值,使用泛型方法的时候,通常不必指明参数类型,编译器会为我们做类型参数推断
  • 泛型类和泛型接口没什么区别
interface Generator<T> {
	T next();
}

// 会报错
class CoffeGenerator  implements Generator<T> {	
}

// 在使用接口时候指定具体类型,而类在创建对象时指定具体类型
class CoffeGenerator  implements Generator<Coffee> {	
}

// 不指定具体类型,将指定类型任务交给子类
public class BasicGenerator<T> implements Generator<T> {
	// 会报错,要去掉static,类上的泛型不能用在静态方法或属性上
	public static T f(T t){
        return t
    }
}
杠杆利用类型参数推断
public class New {
    public static <T> List<T> list(){
        return new ArrayList<T>();
    }
    
    public static void f(List<? extends Fruit> fruits) {
    }

    public static void main(String[] args) {
        List<Object> list = New.list();
        List<Apple> list1 = New.list();
        List<? extends Fruit> list2 = New.list();

        list.add(new Object());
        list1.add(new Apple());
        list2.add(new Fruit());  // 添加报错   
        list2.add(new Apple()); // 添加报错
        list2.get(0).ff(); // 没问题,ff()是Fruit的方法      
        f(list1);
        f(list2);
        
        List<? super Apple> apples = new ArrayList();
        apples.add(new Apple());
		apples.add(new Jonathan()); // 没问题
		apples.add(new Fruit()); // 报错
    }
}
例子
  • 例1
// 元素反作用于泛型类,之前是先确定类上的类型,后确定类里面的元素类型
public static <T> Plate<T>  create(T item) {
    return new Plate<>(item);
}
public class Plate<T> {
    private T item;
    public Plate(T t){item=t;}
    public void set(T t){
        Object o = new Object();
        item=t;
    }
    public T get(){return item;}
}
  • Callable泛型
class TaskWithResult implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        return 1024;
    }
}


interface ExecutorService {
	<T> Future<T> submit(Callable<T> task)
}


Future<Integer> submit = executorService.submit(new TaskWithResult())


interface Future<V> {
	V get()
}
<? extends Parent> 的由来
class Manipulation<T> {
	private T obj;
	public Manipulation(T obj){
		this.obj = obj;
	}

	public void manipulate(){
		// 在这里编译器会报错
		obj.f();
	}
}


class Manipulation<T extends HasF> {
	private T obj;
	public Manipulation(T obj){
		this.obj = obj;
	}

	public void manipulate(){
		// 由于<T extends HasF>,编译通过
		obj.f();
	}
}

// 可以将所有的T替换为HasF,上面例子的泛型没有任何帮助
class Manipulation {
	private HasF obj;
	public Manipulation(HasF obj){
		this.obj = obj;
	}

	public void manipulate(){
		// 由于<T extends HasF>,编译通过
		obj.f();
	}
}

// 这种情况下,? extends SuperClass不能使用SuperClass代替
Class<? extends Fruit> fruit = new Apple(); // 可以
Class<Fruit> fruit = Apple.class; //出错

泛型擦除的问题
  • 在泛型参数内部,无法获得任何关于泛型参数的类型信息
  • 例如:使用反射可以将List<<String的集合添加Object类型
  • 泛型不能显示地引用运行时类型操作,例如转型、instanceof、和new,不过jdk1.8可以用instanceof了
public class Plate<T> {

    public T f(T obj) {
    	// instanceof 在jdk1.8可以用
        if (obj instanceof ArrayList) {
        	// new 报错
            T t = new T();         
            System.out.println(true);
        }
        // 强转报错
        return (Object)obj;
    }
}
  • 为什么ArrayList里的数组是Object[] elementData;,而不是E[] elementData
// 可以new object
this.elementData = new Object[initialCapacity];
// 不可以new E
this.elementData = new Object[initialCapacity];
边界 T extends Test & Hello
class Plate<T extends Apple & Fruit & FruitFactory & Generator>

// Apple10必须同时是Apple & Fruit & FruitFactory & Generator几个的子类
Plate<Apple10> plate = new Plate<>();
  • 例2:内部类
public class Fruit {
    class A{

    }
}

public class Apple extends Fruit{

	// 不能static class B
    class B extends Fruit.A{
    }

    void f(){
        Fruit.A a = new Apple.B();
    }
    
    public static void main(String[] args) {
    	// 创建内部类对象的正确方式
        Apple apple = new Apple();
        Apple.B b = apple.new B();
    }
}
interface Map<K,V> {
	interface Entry<K,V> {
	}
}

class HashMap<K,V> implements Map<K,V>{

	// 这里可以使用static,因为Map.Entry是接口
	static class Node<K,V> implements Map.Entry<K,V> {
	}
}
例3,内部类
interface Iterable<T> {
	Iterator<T> iterator();
}
class ArrayList<E> implements ... Iterable<E> {
	public Iterator<E> iterator() {
        return new Itr();
    }
    
    private class Itr implements Iterator<E> {
    	public boolean hasNext() {}
    	public E next() {
    		// 要引用外部类当前对象的方式
    		Object[] elementData = ArrayList.this.elementData;
    	}
    	public void remove() {}    	
    }
}
  • ArrayList的Iterator不使用内部类会怎么样
// 1.自己实现Iterator接口
class ArrayList<E> implements ... Iterable<E>,Iterator<T> {
	// 模糊了is-a的概念
	// 若ArrayList原来就有hasNext、next、remove方法,会产生冲突
	public Iterator<E> iterator() {
        return this;
    }

	
	public boolean hasNext() {}
   	public E next() {}
   	public void remove() {}  
}

// 2.在外面实现Iterator接口
class Itr implements Iterator<E> {
	// 虽然持有了一个ArrayList,但是只能访问arrayList的public方法
	// 不能像内部类一个访问其private成员
	private ArrayList arrayList;
	Itr() {}
	
  	public boolean hasNext() {}
  	public E next() {}
  	public void remove() {}    	
}

class ArrayList<E> implements ... Iterable<E> {
	public Iterator<E> iterator() {
        return new Itr(this);
    }
}
局部内部类与匿名内部类
public class Outer {

    public Fruit fruit(){
    	// 这个内部类在方法里
        class Pear implements Fruit {}
        return new Pear();
    }
    
    public Fruit fruit(){
    	// 匿名内部类
        return new Fruit(){
        	// 里面是接口方法的实现          
        };
    }
}
匿名内部类与工厂模式
public interface Fruit {
}

public interface FruitFactory {
    Fruit getFruit();
}
class Apple implements Fruit{}

class Pear implements Fruit{}
FruitFactory fruitFactory = new FruitFactory(){
    @Override
    public Fruit getFruit() {
        return new Apple();
    }
};

Fruit fruit = new FruitFactory() {
    @Override
    public Fruit getFruit() {
        return new Pear();
    }
}.getFruit();
嵌套类与普通内部类区别,什么时候使用嵌套类
  • 创建嵌套类对象,并不需要外围类对象,而普通内部类需要:outerObj.new Inner()
  • 嵌套类不能访问外围类的非static成员
  • 普通内部类对象隐式地保存了外围类对象的引用,如果不需要内部类对象与外围类对象有联系,则将内部类声明为static,例如hashmap中的Node
接口内部的类

接口内部的类自动是public和static

interface Map<K,V> {
	interface Entry<K,V> {
	}
}
内部类与闭包,内部类、继承、包含三者比较
  • 闭包是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域;内部类是面向对象的闭包
  • 内部类可以访问外部类的所有成员,继承子类不能访问父类的私有成员,包含也不能访问持有对象的私有成员
例子
  • buildAutowiringMetadata1,2,,3普通写法到内部类进化
 	InjectionMetadata buildAutowiringMetadata1(final Class<?> clazz) {
        for (Field field : getDeclaredFields(clazz)) {
            ...
        }
    }

    InjectionMetadata buildAutowiringMetadata2(final Class<?> clazz) {
        class MyFieldCallback implements FieldCallback {
            void doWith(Field field){
                ...
            }
        }
        
        MyFieldCallback myFieldCallback = new MyFieldCallback();
        for (Field field : getDeclaredFields(clazz)) {
            myFieldCallback.doWith(field);
        }
    }

    InjectionMetadata buildAutowiringMetadata3(final Class<?> clazz) {
        ReflectionUtils.doWithLocalFields(targetClass, field -> {
            ...
        });
    }
函数式编程接口可以有()个方法

只能有一个方法,不然不知道实现哪个

范例
sharedInstance = getSingleton(beanName, () -> {
	return createBean(beanName, mbd, args);
});

Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
	Object singletonObject = this.singletonObjects.get(beanName);
	if (singletonObject == null) {
		singletonObject = singletonFactory.getObject();
		addSingleton(beanName, singletonObject);
	}
	return singletonObject;
}
ReflectionUtils.doWithLocalFields(targetClass, field -> {
	AnnotationAttributes ann = findAutowiredAnnotation(field);
	if (ann != null) {
		...
		// currElements要求必须是final的
		currElements.add(new AutowiredFieldElement(field, required));
	}
});

static void doWithLocalFields(Class<?> clazz, FieldCallback fc) {
	for (Field field : getDeclaredFields(clazz)) {
		fc.doWith(field);
	}
}
函数式接口Runnable
@FunctionalInterface
public interface Runnable {
    public abstract void run();
}
转换为函数式编程
Inter<Integer, String> msg = new Inter<Integer, String>() {
   	public String zhuanhuan(Integer p) {            
   		return  String.valueOf(p);
   	}
}

lambda转换结果:

Inter<Integer, String> msg =(p)-> return String.valueOf(p);
转换为函数式编程-内部类
Consumer c = new Consumer() {
    @Override
    public void accept(Object o) {
        System.out.println(o);
    }
};

转换结果:

Consumer c = (o) -> {
    System.out.println(o);
}; 
简化函数式编程
public interface Inter<P,R> {
    public R zhuanhuan(P p);
}
//lambda
Inter<Integer, String> msg =(p)->String.valueOf(p);

简化为:

Inter<Integer,String> msg = String::valueOf;
上一个例子是静态方法引用,普通方法引用实现呢
interface Inter<P>{
     public int compare(P p1,P p2);
}

实现对string的compareto方法

Inter<String> msg = String::compareTo;
System.out.println(msg.compare("A","B")); // -1
函数式接口功能型、消费型、供给型作用,以及使用

功能型:接受一个参数,返回一个结果,例如string.valueof
消费型:接受参数,不返回结果,例如sout
供给型:接受参数,不返回结果,例如string.touppercase

//功能型接口          
Function<String,Boolean> fun = "hello"::startsWith;
System.out.println(fun.apply("he"));          //true
//消费型接口          
Consumer<String> cons = System.out::println;
cons.accept("hello");                         //hello     
//供给型接口          
Supplier<Stirng> sup = "hello"::toUpperCase;
System.out.println(sup.get());                //HELLO    
consumer的addthen方法使用
Consumer f = System.out::println;
Consumer f2 = n -> System.out.println(n + "-F2");

//执行完F后再执行F2的Accept方法
f.andThen(f2).accept("test");

//连续执行F的Accept方法
f.andThen(f).andThen(f).andThen(f).accept("test1");
举例 ?extends T 的用法。。? super T
Plate<? extends Fruit> p=new Plate<Apple>(new Apple());

但是,不能set值,只能get值,而且get的值不能赋给Apple,只能是fruit或fruit以上的值。

Plate<? super Fruit> p=new Plate<Food>(new Food());

下界<? super T>不影响往里存,但往外取只能放在Object对象里

容器

容器是指()和()

collection 和 map

数组与集合比较(数组大小固定)、(集合里面不能存基本数据类型)、()、()

数组是一块内存连续的空间
数组数据类型固定了,而集合如果不加泛型可以添加任何数据类型

collection接口下有哪些接口,接口有些什么特征

List:有序,元素不唯一
Set:无序,元素唯一
Queue:队列
linkedlist实现了list接口和queue接口,可以当做栈或队列使用

peek与poll的区别:
peek不移除元素,poll移除

list.contains(object)、indexof(object)、remove(object)都会用到object的()方法

equals

equals与==区别

== 比较的是两个对象在对中的地址
equals如果不重写,比较的也是地址
equals是object的方法,不能比较基本类型

		Integer i1 = 127;
        Integer i2 = 127;
        System.out.println(i1 == i2);

输出true

		Integer i1 = 128;
        Integer i2 = 128;
        System.out.println(i1 == i2);

输出false

怎么clone出一个跟原对象互不影响的对象

例如:student对象,student 实现 Cloneable接口,重写clone方法

originList 与 subList 在 collections.shuffle或sort后的变化

不管shuffle的是origin或sub,都会影反应到对方列表中,所以containsAll会返回true

举例说明一个迭代器的好处

遍历list时候,我要写一个遍历方法,遍历set的时候我也要写一个遍历方法,我可以让list和set的实现类都实现Iterable接口,自己返回一个iterator,因此对所有类型的容器遍历,我都只需要遍历iterator即可

遍历map的两种方式

1.遍历keyset,然后get(key)
2.map.entryset.iterator

ArrayList 与 linkedList比价

ArrayList底层是数组,随机访问比linkedlist快
linkedlist底层是链表,插入和删除较快

hashset、treeset、linkedhashset比较

hashset:底层使用哈希存储,查找速度快
treeset:底层使用红黑树,可以排序
linkedhashset:使用了链表维护元素的插入顺序

异常

finally与return

return之后finally总会执行的,finally语句在return语句执行之后,返回之前执行

throwable 、exception、error关系

throwable是exception、error的父类

运行时异常与编译时异常区别,举例常见异常

运行时:ArithmeticException、空指针异常、下标越界异常
编译时:ioException、SQLexception、用户自定义异常

平时是怎么处理异常的

在controller层捕获异常,返回用户提示信息
因为事务已经保证了代码在出现异常后会回滚,所以没有进行其他处理

异常能退出循环吗

添加try-catch程序会继续向下执行,否则终止

for (int i = 0; i < 10; i++) {
    try {
        int j = 1 / 0;
    } catch (Exception e) {
        e.printStackTrace();
    }
    System.out.println("33333");
}
finally可以用来做什么

关闭文件,关闭网络连接,释放数据库连接

异常匹配

就近匹配:第一个匹配到后面就不匹配了
派生类异常对象可以匹配基类

BeansException运行时异常
try {
	return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
	// Explicitly remove instance from singleton cache: It might have been put there
	// eagerly by the creation process, to allow for circular reference resolution.
	// Also remove any beans that received a temporary reference to the bean.
	destroySingleton(beanName);
	// 虽然已抛出,但是调用者可以不处理,因为这运行时异常
	throw ex;
}

设计模式

回忆策略模式、观察者模式、装饰者模式、工厂模式、单例模式、命令模式、适配器模式、外观模式、模板方法模式、迭代器模式、组合模式、状态模式、代理模式
懒汉单例模式怎么不安全了,怎么解决

两个线程同时发现instance == null ,那么都会进入创建对象的代码块
当发现为空之后,先持有一个锁(this.class),持有锁之后再次判断instance是否为null,若为null则new instance

命令模式使用场景与实现

一个接口command,里面有两个方法execute,cancel,将ACommand,Bcommand、Ccommand放入一个command的队列中,派出一个线程执行队列中的command的execute方法,若要回退则反向执行command的cancel方法

类适配器和对象适配器区别

持有对象与继承类的区别

适配器只能包装一个类吗?外观模式可以包装一个类吗

适配器可以包装多个类,外观模式也可以只包装一个类

最少知识原则

外观模式中,本来我需要调用基层类的很多复杂接口,现在只需调用外观类的一个接口,外观类的这个接口隐藏了调用多个基层类的复杂实现

如何理解comparable接口作为排序的模板方法
底层是数组、底层是队列、底层是链表,使用迭代器模式遍历

均实现iterator接口,各自实现hasnext与next方法,例如链表的hasnext的方法实现为element.nextNode == null,next方法为element = element.next

组合模式菜单与菜单项的不同

菜单项是叶子节点,print方法是打印菜单项的内容,菜单里边包含菜单项,其print方法是迭代里面的菜单项,调用菜单项的print方法

状态模式

类有三种状态,四个方法
改为:
类包含三个状态对象,三个对象都实现了四个方法,当然,这个类在一个时刻依然只能是一个状态

什么是远程代理

远程对象的本地代表,本地代表是可以由本地方法调用的对象

什么是RMI

远程方法调用(Remote Method Invocation)

阿里编码规范中约束的分层:终端显示层、开放接口层、请求处理层(web层)、业务逻辑层(service)、通用处理层(manager)、数据持久层(dao)、
终端显示层:各个端的()并执行显示的层,当前主要是js渲染、()渲染、()端展示

模板渲染,jsp,移动端

web层:主要是对访问控制进行(),参数(),()业务()处理

转发,校验,不复用的业务简单

web层与service层处理的业务有什么区别

web层处理简单的不复用的业务

manager层通用业务处理:1.对第三方平台封装的层(),2.对service层通用能力的下沉,例如(),3.service也与dao层交互与manager的dao层交互有什么不同

1.预处理返回结果及异常转换
2.缓存方案,中间件的处理
3.manager层是对多个dao层的组合复用

Java8新特性

Lambda表达式
函数式接口
方法引用与构造器引用
强大的streamAPI
optional类
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值