Java基础知识总结(下)

简介: Java基础知识总结(下)

Java语言的特点,与c++的区别


(1)Java源码会先经过编译器编译成字节码(class文件),然后由JVM中内置的解释器解释成机器码。而C++经过一次编译就形成机器码C++比Java执行效率快,但是Java可以利用JVM跨平台(一次编译,到处运行!)


(2)Java是纯面向对象的语言,所有代码都必须在类定义。而C++中还有面向过程的东西,比如全局变量和全局函数。


(3)C++中有指针,Java中不提供指针直接访问内存,内存更加安全,但是有引用。


(4)C++支持多继承,Java类都是单继承。但是继承都有传递性,同时Java中的接口是多继承,接口可以多实现。


(5)Java 中内存的分配和回收由Java虚拟机实现(自动内存管理机制),会自动清理引用数为0的对象。而在 C++ 编程时,则需要花精力考虑如何避免内存泄漏。


(6)C++运算符可以重载,但是Java中不可以。同时C++中支持强制自动转型,Java中不行,会出现ClassCastException(类型不匹配)。


ps:在 C 语⾔中,字符串或字符数组最后都会有⼀个额外的字符‘\0’来表示结束。但是,Java 语⾔中没有结束符这⼀概念。 这是⼀个值得深度思考的问题,具体原因推荐看这篇⽂章:https://blog.csdn.net/sszgg2006/article/details/49148189

总结:


  • java编译形成字节码,平台无关性(扩展性好),c++一次编译形成机器码(效率高);
  • c++是指针,java是对象的引用;
  • c++多继承,java单继承,多实现;
  • c++需要自己花费时间分配内存和垃圾回收,避免内存泄露,java由jvm实现自动内存管理(分配和回收)。**


ps:Java平台无关性体现在两个方面:


JVM: Java 编译器可生成与计算机体系结构无关的字节码指令,字节码文件不仅可以轻易地在任何机器上解释执行,还可以动态地转换成本地机器代码,转换是由 JVM 实现的,JVM 是平台相关的,屏蔽了不同操作系统的差异。


语言规范: 基本数据类型大小有明确规定,例如 int 永远为 32 位,而 C/C++ 中可能是 16 位、32 位,也可能是编译器开发商指定的其他大小。Java 中数值类型有固定字节数,二进制数据以固定格式存储和传输,字符串采用标准的 Unicode 格式存储。


JDK JRE JVM


  • jdk:开发者工具(针对开发人员),它是功能齐全的 Java SDK。它拥有 JRE 所拥有的一切,还有编译器(javac)和工具(如 javadoc 和 jdb)。它能够创建和编译程序。
  • jre:运行时环境(需要运行java程序的人员),它是运行已编译 Java 程序所需的所有内容的集合,包括 Java 虚拟机(JVM),Java 类库,java 命令和其他的一些基础构件。但是,它不能用于创建新程序。
  • jvm:运行java字节码的虚拟机,JVM 有针对不同系统的特定实现(Windows,Linux,macOS),目的是使用相同的字节码,它们都会给出相同的结果。字节码和不同系统的 JVM 实现是 Java 语言“一次编译,随处可以运行”的关键所在!!!


三者关系


image.png

什么是字节码?采用字节码的好处是什么?


  • 编译型语言:程序在执行之前需要一个专门的编译过程,把程序编译成 为机器语言的文件,运行时不需要重新翻译,直接使用编译的结果就行了。程序执行效率高,依赖编译器,跨平台性差些。如C、C++、Delphi等。
  • 解释型语言:程序不需要编译,程序在运行时才翻译成机器语言,每执行一次都要翻译一次。程序执行效率比较低,依赖解释器,跨平台性好。如Python/JavaScript / Perl /Shell等。


java中的编译器和解释器:


  • Java虚拟机是在机器和编译程序之间加入了一层抽象的虚拟的机器。这台虚拟的机器在任何平台上都提供给编译程序一个的共同的接口。编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,然后由解释器来将虚拟机代码转换为特定系统的机器码执行。在Java中,这种供虚拟机理解的代码叫做字节码(即扩展名为 .class的文件),它不面向任何特定的处理器,只面向虚拟机。
  • 每一种平台的解释器是不同的,但是实现的虚拟机是相同的。Java源程序经过编译器编译后变成字节码,字节码由虚拟机解释执行,虚拟机将每一条要执行的字节码送给解释器,解释器将其翻译成特定机器上的机器码,然后在特定的机器上运行。
  • Java对不同的操作系统有不同的JVM,Java编译器可以生成与平台无关的字节码指令,字节码文件不仅可以轻易地在任何机器上解释执行,还可以动态地转换成本地机器代码,转换是由 JVM 实现的,所以 Java实现了真正意义上的跨平台


注意:字节码到机器码这一步,JVM 类加载器首先加载字节码文件,然后通过解释器逐行解释执行,这种方式的执行速度会相对比较慢。而且,有些方法和代码块是经常需要被调用的(也就是所谓的热点代码),所以后面引进了 JIT 编译器,而 JIT 属于运行时编译。当 JIT 编译器完成第一次编译后,其会将运行频率高的字节码对应的机器码保存下来,下次可以直接使用。而我们知道,机器码的运行效率肯定是高于 Java 解释器的。这也解释了我们为什么经常会说 Java 是编译与解释共存的语言。


采用字节码好处


  • Java语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。
  • 由于字节码并不专对一种特定的机器,因此,Java程序无须重新编译便可在多种不同的计算机上运行。


ps:HotSpot 采⽤了惰性评估(Lazy Evaluation)的做法,根据⼆⼋定律,消耗⼤部分系统资源的只有那⼀⼩部分的代码(热点代码),⽽这也就是 JIT 所需要编译的部分。JVM 会根据代码每次被执⾏的情况收集信息并相应地做出⼀些优化,因此执⾏的次数越多,它的速度就越快。JDK 9 引⼊了⼀种新的编译模式AOT(Ahead of Time Compilation),它是直接将字节码编译成机器码,这样就避免了 JIT 预热等各⽅⾯的开销。JDK ⽀持分层编译和 AOT 协作使⽤。但是 ,AOT 编译器的编译质量是肯定⽐不上 JIT 编译器的。


创建对象的方式有哪些?


  • 通过 new 关键字:这是最常用的一种方式,通过 new 关键字调用类的有参或无参构造方法来创建对象。比如 Object obj = new Object();
  • 通过 Class 类的 newInstance() 方法:这种默认是调用类的无参构造方法创建对象。比如 Person p2 = (Person) Class.forName("com.ys.test.Person").newInstance();
  • 通过 Constructor 类的 newInstance 方法:这和第二种方法类时,都是通过反射来创建对象。通过 java.lang.relect.Constructor 类的 newInstance() 方法指定某个构造器来创建对象。Person p3 = (Person) Person.class.getConstructors()[0].newInstance();
  • 利用 Clone 方法:Clone 是 Object 类中的一个方法,无论何时我们调用一个对象的clone方法,JVM就会创建一个新的对象,将前面的对象的内容全部拷贝进去。通过 对象A.clone() 方法会创建一个内容和对象 A 一模一样的对象 B,clone 克隆,顾名思义就是创建一个一模一样的对象出来。Person p4 = (Person) p3.clone();
  • 反序列化: 当我们序列化和反序列化一个对象,JVM会给我们创建一个单独的对象。序列化是把堆内存中的 Java 对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络节点(在网络上传输)。而反序列化则是把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象模型的过程。


总结:前三种是通过构造函数创建对象,后两个不需要。


深拷贝or浅拷贝?


拷贝的引入


  • 引用拷贝:创建一个指向对象的引用变量的拷贝,即创建一个指向该对象的新的引用变量,teacher与otherteacher指向内存地址相同(只是引用不同),所以肯定指向一个对象Teacher("Taylor",26)。

Teacher teacher = new Teacher("Taylor",26);
Teacher otherteacher = teacher;
System.out.println(teacher);
System.out.println(otherteacher);
// -----------结果-----------------
blog.Teacher@355da254
blog.Teacher@355da254


  • 对象拷贝创建对象本身的副本,输出内存地址不同,即创建了新的对象(不是把原对象的地址赋给一个新的引用变量)。

Teacher teacher = new Teacher("Swift",26);
Teacher otherteacher = (Teacher)teacher.clone();
System.out.println(teacher);
System.out.println(otherteacher);
// -----------结果-----------------
blog.Teacher@355da254
blog.Teacher@4dc63996


注意:深拷贝和浅拷贝都是对象拷贝,都是针对一个已有的对象!对于基本数据类型(元类型),两种拷贝方式都是对值字段的复制(值传递),两者没有区别。


  • 浅拷贝:被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。即对象的浅拷贝会对“主”对象进行拷贝,但不会复制主对象里面的对象。"里面的对象“会在原来的对象和它的副本之间共享。简言之,浅拷贝仅仅复制所考虑的对象,但不复制它所引用的对象(单层的拷贝),故原始对象及其副本引用的同一个对象。
  • 深拷贝:深拷贝是一个整个独立的对象拷贝,深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。简言之,深拷贝把要复制的对象所引用的对象都复制了一遍(多层的拷贝),修改其中一个对象的任何内容,不会影响另一个对象的内容。


浅拷贝实现方式:


  • 首先让定义的实体类实现Cloneable接口。然后重写clone方法,将clone方法的修饰符由protected改为public。这样就可以通过调用clone方法进行浅拷贝。


深拷贝实现方式:


  • 首先是将引用的实体类也实现Cloneable接口(同时重写clone方法,也是修改修饰符为public)。然后同样是让定义的实体类实现Cloneable接口。然后重写clone方法,将clone方法的修饰符由protected改为public。但是方法体需要进行重写,将引用的对象属性调用它本身的clone方法进行赋值,然后将赋值后的对象返回即可。


什么是反射(reflection)机制?应用场景与优缺点。


反射是框架设计的灵魂。使用的前提条件:必须先得到代表字节码的Class类型对象

官方解释:反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个属性和方法;这种动态获取的信息以及动态调用对象的属性方法的功能称为 Java 语言的反射机制。


总结:在运行时,构造任意类的对象,动态的获取类的信息并调用类的属性和方法

如图是类的正常加载过程:反射的原理在于Class对象。熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象,反射的本质:得到Class对象反向获取信息及动态调用对象的属性或者方法。

image.png

既然Java反射可以访问和修改私有成员变量,那封装成private还有意义么?


从OOP封装的角度,可以理解为private只是一种约定(我们要去遵守),是一种设计规范。


反射调用私有方法和属性:


  • getDeclaredMethods():调用私有方法
  • getDeclaredFields():获取私有变量值
  • getConstructor():得到有参的构造函数


注意:setAccessible(true);获取访问权限!


获取Class对象的方式(如何使用反射?):


  • 通过Object类中的getClass方法:因为所有类都继承Object类。getClass方法:返回一个对象的运行时类,进而可以通过Class获取这个类中的相关属性和方法;
  • 任何数据类型(包括基本数据类型)都有一个“静态”的class属性
  • 通过Class类的静态方法:Class.forName(String  className)(常用,即通过全限定类名(绝对路径/真实路径)创建Class对象)

package reflection;
public class Reflection {
    public static void main(String[] args) {
        //第一种方式获取Class对象  
        Student stu1 = new Student();   //通过new方式(构造器床架对象)产生一个Student对象,一个Class对象。
        Class stuClass = stu1.getClass();   //Object类中的getClass()方法,获取Class对象
        System.out.println(stuClass.getName());
        //第二种方式获取Class对象
        Class stuClass2 = Student.class;
        System.out.println(stuClass == stuClass2); //判断第一种方式获取的Class对象和第二种方式获取的是否是同一个
        //第三种方式获取Class对象
        try {
            Class stuClass3 = Class.forName("reflection.Student");  //注意此字符串必须是真实路径,包名.类名
            System.out.println(stuClass3 == stuClass2);  //判断三种方式是否获取的是同一个Class对象
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}


注意:在运行期间,一个类,只有一个Class对象产生。


三种方式常用第三种,第一种对象都有了还要反射干什么。第二种需要导入类的包,依赖太强,不导包就抛编译错误。一般都第三种,可以通过传入一个字符串(全限定类名),也可写在配置文件中等多种方法。


使用反射调用类中的方法,分为三种情况:


  • 调用静态方法
  • 调用公共方法
  • 调用私有方法

package com.interview.chapter4;
class MyReflect {
    // 静态方法
    public static void staticMd() {
        System.out.println("Static Method");
    }
    // 公共方法
    public void publicMd() {
        System.out.println("Public Method");
    }
    // 私有方法
    private void privateMd() {
        System.out.println("Private Method");
    }
    public static void main(String[] args) {
        // 反射调用静态方法
        Class myClass = Class.forName("com.interview.chapter4.MyReflect");
        Method method = myClass.getMethod("staticMd");
        method.invoke(myClass);
        // 反射调用公共方法
        Class myClass = Class.forName("com.interview.chapter4.MyReflect");
        // 创建实例对象(相当于 new )
        Object instance = myClass.newInstance();
        Method method2 = myClass.getMethod("publicMd");
        method2.invoke(instance);
        // 反射调用私有方法
        Class myClass = Class.forName("com.interview.chapter4.MyReflect");
        // 创建实例对象(相当于 new )
        Object object = myClass.newInstance();
        Method method3 = myClass.getDeclaredMethod("privateMd");
        method3.setAccessible(true);
        method3.invoke(object);
    }
}


反射使用总结:


  • 通过 Class.forName("全限定类名"),获取调用类的Class对象;
  • 反射获取类实例要通过 newInstance(),相当于 new 一个新对象;
  • 反射获取方法要通过 getMethod(),获取到类方法之后使用 invoke() 对类方法进行调用(执行一个方法)。如果是类方法为私有方法的话,则需要通过 setAccessible(true) 来修改方法的访问限制,并且获取方法使用getDeclaredMethod()。


反射应用场景


  • 编程工具 IDEA 或 Eclipse 等,在写代码时会有代码(属性或方法名)提示,就是因为使用了反射;
  • 很多知名框架都用到反射机制,通过配置加载不同类,在不修改源码的情况下,注入属性或者调用方法。


例如,Spring 可以通过配置来加载不同的类,调用不同的方法,代码如下所示:

<bean id="person" class="com.spring.beans.Person" init-method="initPerson">
</bean>


例如,MyBatis 在 Mapper 使用外部类的 Sql 构建查询时,代码如下所示:

@SelectProvider(type = PersonSql.class, method = "getListSql")
List<Person> getList();
class PersonSql {
    public String getListSql() {
        String sql = new SQL() {{
            SELECT("*");
            FROM("person");
        }}.toString();
        return sql;
    }
}


  • 数据库连接池,也会使用反射调用不同类型的数据库驱动,代码如下所示:

String url = "jdbc:mysql://127.0.0.1:3306/mydb";
String username = "root";
String password = "root";
Class.forName("com.mysql.jdbc.Driver");
Connection connection = DriverManager.getConnection(url, username, password);


  • Web服务器中利用反射调用了Sevlet的服务方法。
  • 另外,像 Java 中的一大利器 注解 的实现也用到了反射。为什么你使用 Spring 的时候 ,一个@Component注解就声明了一个类为 Spring Bean 呢?为什么你通过一个 @Value注解就读取到配置文件中的值呢?究竟是怎么起作用的呢?这些都是因为你可以基于反射分析类,然后获取到类/属性/方法/方法的参数上的注解。你获取到注解之后,就可以做进一步的处理。


优缺点


  • 优点:可以动态执行,节省资源在运行期间根据业务功能动态执行方法、访问属性,最大限度发挥了java的灵活性。
  • 缺点:对性能有影响,这类操作总是慢于直接执行java代码,要先生成Class对象。


动态代理(设计模式),常见的两种动态代理的实现?


写在前:静态代理:每个代理类只能为一个接口服务,这样会产生很多代理类。普通代理模式,代理类Proxy的Java代码在JVM运行时就已经确定了,也就是静态代理在编码编译阶段就确定了Proxy类的代码。而动态代理是指在JVM运行过程中,动态的创建一个类的代理类,并实例化代理对象。


动态代理:首先它是一个代理机制,代理可以看作是对调用目标的一个包装,这样我们对目标代码的调用不是直接发生的,而是通过代理完成,通过代理可以让调用者与实现者之间解耦。比如进行 RPC 调用,通过代理,可以提供更加友善的界面;还可以通过代理,做一个全局的拦截器。代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。解决的问题:直接访问一个对象带来的问题。


应用场景:


  • 经典应用有 Spring AOP数据查询、例如,依赖注入 @Autowired 和事务注解 @Transactional 等,都是利用动态代理实现的;
  • 封装一些rpc调用;
  • 通过代理实现一个全局拦截器等。


动态代理与反射的关系:反射可以用来实现动态代理,但动态代理还有其他的实现方式,比如 ASM(一个短小精悍的字节码操作框架)、cglib 等。


jdk动态代理:


在java的类库中,java.util.reflect.Proxy类就是其用来实现动态代理的顶层类。可以通过Proxy类的静态方法Proxy.newProxyInstance()方法动态的创建一个类的代理类,并实例化。由它创建的代理类都是Proxy类的子类。


image.png

JDK动态代理实现步骤:


  • 编写需要被代理的类和接口
  • 编写代理类,需要实现 InvocationHandler 接口,重写 invoke() 方法;
  • 使用Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)动态创建代理类对象,通过代理类对象调用业务方法。


注意: JDK Proxy 只能代理实现接口的类(即使是 extends 继承类也是不可以代理的)


cglib实现动态代理:


  • CGLIB是一个高性能的代码生成类库,被Spring广泛应用。其底层是通过ASM字节码框架生成类的字节码,达到动态创建类的目的。


ps:Spring AOP动态代理的实现方式有两种:cglib 和 JDK 原生动态代理。


image.png

cglib动态代理的实现步骤:


  • 创建被代理的目标类。
  • 创建一个方法拦截器类,并实现CGLIB的MethodInterceptor接口的intercept()方法。
  • 通过Enhancer类增强工具,创建目标类的代理类。
  • 利用代理类进行方法调用,就像调用真实的目标类方法一样。


要是用 cglib 实现要添加对 cglib 的依赖,如果是 maven 项目的话,直接添加以下代码:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.2.12</version>
</dependency>


cglib 的具体实现,请参考以下代码:

class Panda {
    public void eat() {
        System.out.println("The panda is eating");
    }
}
class CglibProxy implements MethodInterceptor {
    private Object target; // 代理对象
    public Object getInstance(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        // 设置父类为实例类
        enhancer.setSuperclass(this.target.getClass());
        // 回调方法
        enhancer.setCallback(this);
        // 创建代理对象
        return enhancer.create();
    }
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("调用前");
        Object result = methodProxy.invokeSuper(o, objects); // 执行方法调用
        System.out.println("调用后");
        return result;
    }
}
public static void main(String[] args) {
    // cglib 动态代理调用
    CglibProxy proxy = new CglibProxy();
    Panda panda = (Panda)proxy.getInstance(new Panda());
    panda.eat();
}


由以上代码可以知道,cglib 的调用通过实现 MethodInterceptor 接口的 intercept 方法,调用 invokeSuper 进行动态代理的。它可以直接对普通类(可以有子类的普通类,但不能代理最终类)进行动态代理,并不需要像 JDK 代理那样,需要通过接口来完成, Spring 的动态代理也是通过 cglib 实现的。


注意:cglib 底层是通过子类继承被代理对象的方式实现动态代理的(即,动态的生成被代理类的子类),因此代理类不能是最终类(final),否则就会报错 java.lang.IllegalArgumentException: Cannot subclass final class xxx。


JDK原生态动态代理和CGlib区别


  • JDK 原生动态代理:只能代理实现接口的类(即使是 extends 继承类也是不可以代理的),不需要添加任何依赖,可以平滑的支持 JDK 版本的升级;
  • cglib 不需要实现接口,底层通过子类继承被代理对象的方式实现动态代理。可以直接代理普通类(但不能代理final修饰的类),需要添加依赖包,性能更高。


两者的区别:


  • JDK 动态代理:基于 Java 反射机制实现,必须要实现了接口的业务类(extends 继承类不可代理)才能用这种办法生成代理对象。
  • CGLib 动态代理:基于 ASM 机制实现,通过生成业务类的子类作为代理类(本质是子类继承被代理类的方法),所以代理的类不能是 final 修饰的。


JDK Proxy 的优势:


  • 最小化依赖关系,减少依赖意味着简化开发和维护,JDK 本身的支持,可能比 CGLib 更加可靠。
  • 平滑进行 JDK 版本升级,而字节码类库通常需要进行更新以保证在新版 Java 上能够使用。
  • 代码实现简单。


基于类似 CGLib 框架的优势:


  • 无需实现接口,达到代理类无侵入。故CGLib适合那些没有接口抽象的类代理。
  • 只操作我们关心的类,而不必为其他相关类增加工作量。


ps:为什么 JDK 原生的动态代理必须要通过接口来完成?


这是由于 JDK 原生设计的原因,动态代理的实现方法 newProxyInstance() 的源码如下:

/**
 * ......
 * @param   loader the class loader to define the proxy class
 * @param   interfaces the list of interfaces for the proxy class to implement
 * ......
 */ 
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
// 省略其他代码


前两个参数的声明:


  • loader:为类加载器,也就是 target.getClass().getClassLoader()
  • interfaces:接口代理类的接口实现列表


因此,要使用 JDK 原生的动态只能通过实现接口来完成。


什么是注解,什么是元注解?


注解是一种标记,使类或接口附加额外信息,帮助编译器和 JVM 完成一些特定功能,例如 @Override 标识一个方法是重写方法。


原理:注解的底层也是使用反射实现的。可以发现注解的本质就是接口,这个接口继承了jdk里面的Annotation接口。


元注解是自定义注解的注解,例如:


  • @Target:约束作用位置,值是 ElementType 枚举常量,包括 METHOD 方法、VARIABLE 变量、TYPE 类/接口、PARAMETER 方法参数、CONSTRUCTORS 构造方法和 LOACL_VARIABLE 局部变量等。
  • @Rentention:约束生命周期,值是 RetentionPolicy 枚举常量,包括 SOURCE 源码、CLASS 字节码和 RUNTIME 运行时。
  • @Documented:表明这个注解应该被 javadoc 记录。


注解的作用:


  • 生成文档,常用的有@param@return等。
  • 替代配置文件的作用,尤其是在spring等一些框架中,使用注解可以大量的减少配置文件的数量。比如@Configuration标识这是一个配置类,@ComponentScan("spring.ioc.stu")配置包扫描路径 :

@Configuration
@ComponentScan("spring.ioc.stu")
public class SpringConfiguration {
     xxx;
}


  • 检查代码的格式,如@Override,标识某一个方法是否覆盖了它的父类的方法。


三大内置注解:


  • @Deprecated 已过期,表示方法是不被建议使用的
  • @Override 重写,标识覆盖它的父类的方法
  • @SuppressWarnings 压制警告,抑制警告
相关文章
|
1月前
|
Java 程序员 调度
Java中的多线程编程:基础知识与实践
【4月更文挑战第5天】 在现代软件开发中,多线程编程是一个不可或缺的技术要素。它允许程序员编写能够并行处理多个任务的程序,从而充分利用多核处理器的计算能力,提高应用程序的性能。Java作为一种广泛使用的编程语言,提供了丰富的多线程编程支持。本文将介绍Java多线程编程的基础知识,并通过实例演示如何创建和管理线程,以及如何解决多线程环境中的常见问题。
|
11天前
|
IDE Java 开发工具
Java从入门到精通:1.3.1实践编程巩固基础知识
Java从入门到精通:1.3.1实践编程巩固基础知识
|
11天前
|
Java
Java基础知识整理,驼峰规则、流程控制、自增自减
在这一篇文章中我们总结了包括注释、关键字、运算符的Java基础知识点,今天继续来聊一聊命名规则(驼峰)、流程控制、自增自减。
36 3
|
11天前
|
Java 开发者
Java基础知识整理,注释、关键字、运算符
在日常的工作中,总会遇到很多大段的代码,逻辑复杂,看得人云山雾绕,这时候若能言简意赅的加上注释,会让阅读者豁然开朗,这就是注释的魅力!
39 11
|
1月前
|
搜索推荐 Java
Java基础(快速排序算法)
Java基础(快速排序算法)
24 4
|
2月前
|
关系型数据库 Java 开发工具
Java入门高频考查基础知识9(15问万字参考答案)
本文探讨了Spring Cloud的工作原理,包括注册中心的心跳机制、服务发现机制,以及Eureka默认的负载均衡策略。同时,概述了Spring Boot中常用的注解及其实现方式,并深入讨论了Spring事务的注解、回滚条件、传播性和隔离级别。文章还介绍了MySQL的存储引擎及其区别,特别关注了InnoDB如何实现MySQL的事务处理。此外,本文还详细探讨了MySQL索引,包括B+树的原理和设计索引的方法。最后,比较了Git和SVN的区别,并介绍了Git命令的底层原理及流程。
32 0
Java入门高频考查基础知识9(15问万字参考答案)
|
2月前
|
存储 缓存 算法
Java入门高频考查基础知识4(字节跳动面试题18题2.5万字参考答案)
最重要的是保持自信和冷静。提前准备,并对自己的知识和经验有自信,这样您就能在面试中展现出最佳的表现。祝您面试顺利!Java 是一种广泛使用的面向对象编程语言,在软件开发领域有着重要的地位。Java 提供了丰富的库和强大的特性,适用于多种应用场景,包括企业应用、移动应用、嵌入式系统等。下是几个面试技巧:复习核心概念、熟悉常见问题、编码实践、项目经验准备、注意优缺点、积极参与互动、准备好问题问对方和知其所以然等,多准备最好轻松能举一反三。
61 0
Java入门高频考查基础知识4(字节跳动面试题18题2.5万字参考答案)
|
2月前
|
存储 算法 JavaScript
Java入门高频考查算法逻辑基础知识3-编程篇(超详细18题1.8万字参考编程实现)
解决这类问题时,建议采取下面的步骤: 理解数学原理:确保你懂得基本的数学公式和法则,这对于制定解决方案至关重要。 优化算法:了解时间复杂度和空间复杂度,并寻找优化的机会。特别注意避免不必要的重复计算。 代码实践:多编写实践代码,并确保你的代码是高效、清晰且稳健的。 错误检查和测试:要为你的代码编写测试案例,测试标准的、边缘情况以及异常输入。 进行复杂问题简化:面对复杂的问题时,先尝试简化问题,然后逐步分析和解决。 沟通和解释:在编写代码的时候清晰地沟通你的思路,不仅要写出正确的代码,还要能向面试官解释你的
34 0
|
2月前
|
存储 Java 编译器
Java入门高频考查基础知识2(超详细28题2.5万字答案)
多态是面向对象编程中的一个重要概念,它允许不同类的对象对同一消息作出不同的响应。在具体实现上,多态允许一个父类的引用指向其子类的对象,并根据实际指向的对象的类型来调用相应的方法。在 Java 中,多态可以通过以下几种方式实现:在同一个类中,方法名相同,但形参列表不同,实现了多态。子类可以重写(覆盖)其父类的方法,实现多态。在父类引用中调用该方法时,根据实际指向的子类对象的类型来调用相应的方法实现。
42 0
|
2月前
|
Java 数据库连接 API
Java 学习路线:基础知识、数据类型、条件语句、函数、循环、异常处理、数据结构、面向对象编程、包、文件和 API
Java 是一种广泛使用的、面向对象的编程语言,始于1995年,以其跨平台性、安全性和可靠性著称,应用于从移动设备到数据中心的各种场景。基础概念包括变量(如局部、实例和静态变量)、数据类型(原始和非原始)、条件语句(if、else、switch等)、函数、循环、异常处理、数据结构(如数组、链表)和面向对象编程(类、接口、继承等)。深入学习还包括包、内存管理、集合框架、序列化、网络套接字、泛型、流、JVM、垃圾回收和线程。构建工具如Gradle、Maven和Ant简化了开发流程,Web框架如Spring和Spring Boot支持Web应用开发。ORM工具如JPA、Hibernate处理对象与数
95 3