刷完牛客网910道Java题目,快速总结上万字,带你扫清Java基础面试障碍

花时间刷完了牛客网专项训练所有的Java题,终于有点时间,决定肝一篇Java基础总结,带你扫清Java基础面试障碍!

在这里插入图片描述
在这里插入图片描述

1、Java关键字

在这里插入图片描述
分组一下:
   关键字一律用小写字母标识,按其用途划分为如下几组。
(1)用于数据类型。
   用于数据类型的关键字有 boolean、byte、char、 double、 float、int、long、new、short、void、instanceof。
(2)用于语句。
   用于语句的关键字有break、case、 catch、 continue、 default 、do、 else、 for、 if、return、switch、try、 while、 finally、 throw、this、 super。
(3)用于修饰
   用于修饰的关键字有 abstract、final、native、private、 protected、public、static、synchronized、transient、 volatile。
(4)用于方法、类、接口、包和异常。
   用于方法、类、接口、包和异常的关键字有 class、 extends、 implements、interface、 package、import、throws。
   还有些关键字,如 future、 generic、 operator、 outer、rest、var等都是Java保留的没有意义的关键字。
另外,Java还有3个保留字:goto、const、null。它们不是关键字,而是文字。包含Java定义的值。和关键字一样,它们也不可以作为标识符使用。

2、向上或向下转型

Base base = new Son();
base.method();
base.methodB();

记住口诀:编译看左边,运行看右边。
意思是说编译时候,看左边有没有该方法,运行的时候结果看 new 的对象是谁,就调用的谁。

3、类初始化顺序

class A {
    public A() {
        System.out.println("class A");
    }

    {
        System.out.println("I'm A class");
    }

    static {
        System.out.println("class A static");
    }
}

class B extends A {
    public B() {
        System.out.println("class B");
    }

    {
        System.out.println("I'm B class");
    }

    static {
        System.out.println("class B static");
    }

    public static void main(String arg[]) {
        new B();
    }
}

输出顺序:

class A static
class B static
I'm A class
class A
I'm B class
class B

顺序应该是:父类静态域——>子类静态域——>父类成员初始化——>父类构造块——>父类构造方法——>子类成员初始化——>子类构造块——>子类构造方法;

4、ASCII码表

在这里插入图片描述

5、 权限修饰符

在这里插入图片描述

6、位运算符

  • &逻辑与:有false则false。
  • |逻辑或:有true则true。
  • ^逻辑异或:相同为false,不同为true。
  • !逻辑非:非false则true,非true则false。

7、静态变量和成员变量的区别

  • A:所属不同
    • 静态变量属于类,所以也称为为类变量
    • 成员变量属于对象,所以也称为实例变量(对象变量)
  • B:内存中位置不同
    • 静态变量存储于方法区的静态区
    • 成员变量存储于堆内存
  • C:内存出现时间不同
    • 静态变量随着类的加载而加载,随着类的消失而消失
    • 成员变量随着对象的创建而存在,随着对象的消失而消失
  • D:调用不同
    • 静态变量可以通过类名调用,也可以通过对象调用
    • 成员变量只能通过对象名调用

8、Java创建对象的方式有几种?

(1)使用 new 关键字(最常用)

ObjectName obj = new ObjectName();

(2)使用反射的Class类的newInstance()方法

ObjectName obj = ObjectName.class.newInstance();

(3)使用反射的Constructor类的newInstance()方法

ObjectName obj = ObjectName.class.getConstructor.newInstance();

(4)使用对象克隆clone()方法

ObjectName obj = obj.clone();

(5)使用反序列化(ObjectInputStream)的readObject()方法

 try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(FILE_NAME))) {
 	ObjectName obj = ois.readObject();
 }

9、值传递和引用传递

答:值传递不可以改变原变量的内容和地址;
引用传递不可以改变原变量的地址,但可以改变原变量的内容;

10、String和StringBuffer、StringBuilder的区别?

答:String类是不可变类(final修饰),即一旦一个String对象被创建以后,包含在这个对象中的字符序列是不可改变的,直至这个对象被销毁。StringBuffer是线程安全的,StringBuilder线程不安全,但效率高。
实际使用:
如果要操作少量的数据用:String
单线程操作字符串缓冲区下操作大量数据:StringBuilder
多线程操作字符串缓冲区下操作大量数据:StringBuffer

11、重载和重写的区别?

答:重载(Overload):在同一个类中,如果多个方法,名字相同、参数不同,即称为重载。在编译器眼里,方法名称+参数类型+参数个数,组成一个唯一键,称为方法签名,JVM通过这个唯一键决定调用哪个重载的方法。
重写(Override):方法重写是存在子父类之间的,子类定义的方法与父类中的方法具有相同的名字、参数、返回类型
口诀看这里:
方法重写的记忆口诀“ 一大两小两同”

  • 一大:子类的方法访问权限控制符只能相同或变大。
  • 两小:抛出异常和返回值只能变小, 能够转型成父类对象。子类的返回值、抛出异常类型必须与父类的返回值、抛出异常类型存在继承关系。
  • 两同:方法名和参数必须完全相同。

12、集合框架中的泛型有什么优点?

答:泛型提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型。泛型限制了集合容纳的对象类型,如果添加其它类型的任何元素,它会在编译时报错。这避免了在运行时出现 ClassCastException。泛型也使得代码整洁,我们不需要使用显式转换和 instanceOf 操作符。它也给运行时带来好处,因为不会产生类型检查的字节码指令。

13、final, finally, finalize的区别?

答:final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
内部类要访问局部变量,局部变量必须定义成final类型,例如,一段代码……
finally是异常处理语句结构的一部分,表示总是执行。
finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。JVM不保证此方法总被调用。

14、Exception和Error的区别?

答:Exception 和 Error 都是继承了 Throwable类,在 Java 中只有 Throwable 类型的实例才可以被抛出(throw)或者捕获(catch),它是异常处理机制的基本组成类型。Exception 和 Error 体现了 Java 平台设计者对不同异常情况的分类。
在这里插入图片描述
Exception:程序正常运行中,可以预料的意外情况,可能并且应该被捕获,进行相应处理。
Error:是指在正常情况下,不大可能出现的情况,绝大部分的 Error 都会导致程序(比如 JVM 自身)处于非正常的、不可恢复状态。既然是非正常情况,所以不便于也不需要捕获,常见的比如OutOfMemoryError之类,都是 Error 的子类。

Exception 又分为可检查(checked)异常和不检查(unchecked)异常。
● 可检查异常在源代码里必须显式地进行捕获处理,这是编译期检查的一部分。
● 不检查异常就是所谓的运行时异常,类似NullPointerException、ArrayIndexOutOfBoundsException之类,通常是可以编码避免的逻辑错误,具体根据需要来判断是否需要捕获,并不会在编译期强制要求。

15、throw 和throws 的区别?

答:位置不同:throws 用在函数上,后面跟的是异常类,可以跟多个;而throw 用在函数内,后面跟的是异常对象。
功能不同:
(1)throws 用来声明异常,让调用者只知道该功能可能出现的问题,可以给出预先的处理方式;throw 抛出具体的问题对象,执行到throw,功能就已经结束了,跳转到调用者,并
将具体的问题对象抛给调用者。也就是说throw 语句独立存在时,下面不要定义其他语
句,因为执行不到。
(2) throws 表示出现异常的一种可能性,并不一定会发生这些异常;throw 则是抛出了异常,执行throw 则一定抛出了某种异常对象。
(3)两者都是消极处理异常的方式,只是抛出或者可能抛出异常,但是不会由函数去处理异常,真正的处理异常由函数的上层调用处理。

16、什么是Java反射机制?

答:Java 中的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能成为Java 语言的反射机制。
它的功能:
(1)在运行时判定任意一个对象所属的类;
(2)在运行时构造任意一个类的对象;
(3)在运行时判定任意一个类所具有的成员变量和方法;
(4)在运行时调用任意一个对象的方法;
(5)生成动态代理;

17、获取Class 对象的方法?

答:(1)调用某个对象的getClass()方法;

Person p=new Person();
Class clazz=p.getClass();

(2)调用某个类的class 属性来获取该类对应的Class 对象;

Class clazz=Person.class;

(3)使用Class 类中的forName()静态方法(最安全/性能最好);

Class clazz=Class.forName("类的全路径"); 

18、什么是Java复制?

答:将一个对象的引用复制给另外一个对象,一共有三种方式。
第一种方式是直接赋值,第二种方式是浅拷贝,第三种是深拷贝。
(1)直接赋值
A a1 = a2,实际上复制的是引用,也就是说a1 和a2 指向的是同一个对象。因此,当a1 变化的时候,a2 里面的成员变量也会跟着变化。
(2)浅复制(复制引用但不复制引用的对象)
创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。
(3)深复制(复制对象和其应用对象)
深拷贝不仅复制对象本身,而且复制对象包含的引用指向的所有对象。

19、什么是Java序列化?

答:序列化:将java对象转换为字节序列的过程称为对象的序列化;
在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。必须注意地是,对象序列化保存的是对象的“状态”,即它的成员变量。由此可知,对象序列化不会关注类中的静态变量。
为什么要序列化?
(1)持久化(2)网络传输

20、为啥要实现Serializable接口?

答:这个接口其实是个空接口,那么实现它有什么用呢?其实,当我们让实体类实现Serializable接口时,其实是在告诉JVM此类可被序列化,可被默认的序列化机制序列化。

21、Transient 关键字有什么作用?

答:简而言之,被transient修饰的变量不参与序列化和反序列化。

22、截止JDK1.8版本,java并发框架支持锁包括?

● 自旋锁:自旋,jvm默认是10次吧,有jvm自己控制。for去争取锁
● 阻塞锁:被阻塞的线程,不会争夺锁。
● 可重入锁:多次进入改锁的域
● 读写锁
● 互斥锁:锁本身就是互斥的
● 悲观锁:不相信,这里会是安全的,必须全部上锁
● 乐观锁:相信,这里是安全的。
● 公平锁:有优先级的锁
● 非公平锁:无优先级的锁
● 偏向锁:无竞争不锁,有竞争挂起,转为轻量锁
● 对象锁:锁住对象
● 线程锁
● 锁粗化:多锁变成一个,自己处理
● 轻量级锁:CAS 实现
● 锁消除:偏向锁就是锁消除的一种
● 锁膨胀:jvm实现,锁粗化
● 信号量:使用阻塞锁 实现的一种策略
● 排它锁:X锁,若事务T对数据对象A加上X锁,则只允许T读取和修改A,其他任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。这就保证了其他事务在T释放A上的锁之前不能再读取和修改A。

23、JDK提供的用于并发编程的同步器有哪些?

答:(1)Semaphore
   可以很轻松完成信号量控制,Semaphore可以控制某个资源可被同时访问的个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。
(2)CyclicBarrier
   主要的方法就是一个:await()。await()方法没被调用一次,计数便会减少1,并阻塞住当前线程。当计数减至0时,阻塞解除,所有在此 CyclicBarrier 上面阻塞的线程开始运行。
(3)CountDownLatch
   直译过来就是倒计数(CountDown)门闩(Latch)。倒计数不用说,门闩的意思顾名思义就是阻止前进。在这里就是指 CountDownLatch.await() 方法在倒计数为0之前会阻塞当前线程。

24、HttpServlet容器响应Web客户请求流程

(1)Web客户向Servlet容器发出Http请求;
(2) Servlet容器解析Web客户的Http请求;
(3)Servlet容器创建一个HttpRequest对象,在这个对象中封装Http请求信息;
(4)Servlet容器创建一个HttpResponse对象;
(5) Servlet容器调用HttpServlet的service方法,这个方法中会根据request的Method来判断具体是执行doGet还是doPost,把HttpRequest和HttpResponse对象作为service方法的参数传给HttpServlet对象;
(6) HttpServlet调用HttpRequest的有关方法,获取HTTP请求信息;
(7)HttpServlet调用HttpResponse的有关方法,生成响应数据;
(8)Servlet容器把HttpServlet的响应结果传给Web客户。

25、内部类的访问特点

● 内部类可以直接访问外部类的成员,包括私有。
● 外部类要访问内部类的成员,必须创建对象。
● 外部类名.内部类名 对象名 = 外部类对象.内部类对象。

26、数组和集合的区别

(1) 存储

  • 数组既可以存储基本数据类型,又可以存储引用数据类型,基本数据类型存储的是值,引用数据类型存储的是地址值。
  • 集合只能存储引用数据类型(对象)集合中也可以存储基本数据类型,但是在存储的时候会自动装箱变成对象。
    (2)长度
  • 数组长度是固定的,不能自动增长。
  • 集合的长度的是可变的,可以根据元素的增加而增长。

27、synchronized关键字和volatile关键字比较?

● volatile关键字是线程同步的轻量级实现,所以volatile性能肯定比synchronized关键字要好。但是volatile关键字只能用于变量而synchronized关键字可以修饰方法以及代码块。synchronized关键字在JavaSE1.6之后进行了主要包括为了减少获得锁和释放锁带来的性能消耗而引入的偏向锁和轻量级锁以及其它各种优化之后执行效率有了显著提升,实际开发中使用 synchronized 关键字的场景还是更多一些。
● 多线程访问volatile关键字不会发生阻塞,而synchronized关键字可能会发生阻塞。
● volatile关键字能保证数据的可见性,但不能保证数据的原子性。synchronized关键字两者都能保证。
● volatile关键字主要用于解决变量在多个线程之间的可见性,而 synchronized关键字解决的是多个线程之间访问资源的同步性。

28、以下哪种方式实现的单例是线程安全的

● 饿汉式(线程安全,调用效率高,但是不能延时加载);
● 懒汉式(线程安全,调用效率不高,但是能延时加载);
● Double CheckLock实现单例:DCL也就是双重锁判断机制(由于JVM底层模型原因,偶尔会出问题,不建议使用);
● 静态内部类实现模式(线程安全,调用效率高,可以延时加载);
● 枚举类(线程安全,调用效率高,不能延时加载,可以天然的防止反射和反序列化调用)。

29、集合结构

在这里插入图片描述

30、服务端和客户端的Socker交互

在这里插入图片描述

public class TcpServer {
    public static void main(String[] args) throws Exception {
        // Server端监听10000端口
        ServerSocket serverSocket = new ServerSocket(10000);
        while(true){
            // 等待客户端连接,此时进入阻塞状态
            Socket socket = serverSocket.accept();
            System.out.println("Connected: " + socket.getRemoteSocketAddress());
            // 从Socket读取数据
            InputStream inputStream = socket.getInputStream();
            byte[] b = new byte[1024];
            int length = inputStream.read(b);
            System.out.println(length + " Bytes Received");
        }

    }
}
public class TcpClient {

    /**
     * @param args
     * @throws IOException
     * @throws UnknownHostException
     */
    public static void main(String[] args) throws Exception{
        // TODO Auto-generated method stub

        //1.建立TCP连接
        Socket client = null;
        try {
            client = new Socket("127.0.0.1", 10006);
            client.setSoTimeout(10000);
        }catch (Exception e){
            throw new Exception("TCP连接异常");
        }

        //2、传输内容
        String content = "这是一个JAVA模拟客户端";
        byte[] bstream = content.getBytes("UTF-8");//字节流
        OutputStream os = client.getOutputStream();
        os.write(bstream);

        //3、关闭TCP连接
        if (null != client ){
            client.close();
        }
    }

}

31、常用的排序

在这里插入图片描述

32、如何判断哪些内存需要回收?

答:(1)引用计数(存储在堆对象数据里面(对象头)):一个对象被引用一次,那么应用计数就加1,如果说没有引用,减1 引用计数等于0,就表示这个对象需要回收。(有循环引用问题)
(2)可达性分析法:这个算法的基本思想是通过一系列称为“GC Roots”的对象作为起始点,从这些节点向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链(即GC Roots到对象不可达)时,则证明此对象是不可用的。(注意:不可达对象不等价于可回收对象,不可达对象变为可回收对象至少要经过两次标记过程。两次标记后仍然是可回收对象,则将面临回收。)

33、简述 java 垃圾回收机制?

答:在 java 中,程序员是不需要显示的去释放一个对象的内存的,而是由虚拟机自行执行。在JVM 中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者当前堆内存不足时,才会触发执行,扫面那些没有被任何引用的对象,并将它们添加到要回收的集合中,进行回收。

34、说一下常见的垃圾回收算法?

答:(1)标记-清除算法(年老代)
产生大量的内存碎片,效率也不高。适用于存活对象较多的情况下比较高效,适用于年老代(即旧生代)。
(2)复制算法(新生代)
时间换空间,解决了效率问题,但浪费了空间。适用于存活对象较少的情况下比较高效,适用于年轻代(即新生代)。
(3)标记-整理算法(年老代)
解决对象都存活的问题,是标记-清除算法的优化,将所有的存活对象压缩到内存的一端。之后,清理边界外所有的空间。适用于年老代(即旧生代)。
(4)分代收集算法
分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation),在堆区之外还有一个代就是永久代(Permanet Generation)。新生代的特点是每次垃圾回收时都有大量的对象需要被回收,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代的特点是每次垃圾收集时只有少量对象需要被回收,对象存活率高,就可使用“标记-清理”或“标记-整理”算法来进行回收。

35、Minor GC 与 Full GC 分别在什么时候发生?

答:新生代内存不够用时候发生 MGC 也叫 YGC,JVM 内存不够的时候发生 FGC

36、classload类加载过程?

答:JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程。

(1)加载
将class字节码文件加载到内存中,通过一个类的全限定名获取该类的二进制流,并将该二进制流中的静态存储结构转换成方法区中的运行时数据(静态变量、静态代码块、常量池等),在堆中生成一个Class类对象代表这个类(反射原理),作为方法区类数据的访问入口。
(2)验证
确保加载的类信息符合JVM规范,没有安全方面的问题。
● 文件格式验证:验证字节流是否符合 Class 文件的规范,如主次版本号是否在当前虚拟机范围内,常量池中的常量是否有不被支持的类型.
● 元数据验证:对字节码描述的信息进行语义分析,如这个类是否有父类,是否集成了不被继承的类等。
● 字节码验证:是整个验证过程中最复杂的一个阶段,通过验证数据流和控制流的分析,确定程序语义是否正确,主要针对方法体的验证。如:方法中的类型转换是否正确,跳转指令是否正确等。
● 符号引用验证:这个动作在后面的解析过程中发生,主要是为了确保解析动作能正确执行。
(3)准备
正式为类变量(static变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配。注意此时的设置初始值为默认值,具体赋值在初始化阶段完成。
(4)解析
虚拟机常量池内的符号引用替换为直接引用(地址引用)的过程。
(5)初始化
初始化阶段对静态变量和静态代码块执行初始化工作。到了初始化阶段,才真正开始执行类中定义的Java 程序代码。
初始化顺序:父类的静态变量->父类的静态代码块->子类的静态变量->子类的静态代码块->父类的非静态变量->父类的非静态代码块->父类的构造方法->子类的非静态变量->子类的非静态代码块->子类的构造方法。

37、类加载器有几种?

答:(1)启动类加载器(Bootstrap ClassLoader)
负责加载加载 Java 核心类库,无法被 Java 程序直接引用。 在JAVA_HOME\lib 目录中的,或通过-Xbootclasspath参数指定路径中的,且被虚拟机认可(按文件名识别,如rt.jar)的类。
(2)扩展类加载器(Extension ClassLoader)
负责加载Java的扩展库,在 JAVA_HOME\lib\ext 目录中的,或通过java.ext.dirs系统变量指定路径中的类库。
(3)应用程序类加载器(Application ClassLoader)
负责加载用户路径(classpath)上的类库。 JVM通过双亲委派模型进行类的加载,当然我们也可以通过继承java.lang.ClassLoader实现自定义的类加载器。
在这里插入图片描述

38、说一下双亲委派?

答:当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载。
   有什么好处:
(1)基于双亲委派模型规定的这种带有优先级的层次性关系,虚拟机运⾏程序时就能够避免类的重复加载。
(2)双亲委派模型能够避免核⼼类篡改。

39、JAVA 中的引用类型?

答:(1)强引用
在Java中最常见的就是强引用,把一个对象赋给一个引用变量,这个引用变量就是一个强引用。当一个对象被强引用变量引用时,它处于可达状态,它是不可能被垃圾回收机制回收的,即使该对象以后永远都不会被用到JVM也不会回收。因此强引用是造成Java内存泄漏的主要原因之一。
(2)软引用
软引用需要用SoftReference类来实现,对于只有软引用的对象来说,当系统内存足够时它不会被回收,当系统内存空间不足时它会被回收。软引用通常用在对内存敏感的程序中。
(3)弱引用
弱引用需要用WeakReference类来实现,它比软引用的生存期更短,对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管JVM的内存空间是否足够,总会回收该对象占用的内存。
(4)虚引用
虚引用需要PhantomReference类来实现,它不能单独使用,必须和引用队列联合使用。虚引用的主要作用是跟踪对象被垃圾回收的状态。

40、HashMap底层原理?

答:博文链接:一文看懂HashMap底层原理

41、如何解决HashMap碰撞问题?

答:(1)开放地址法
开放地执法有一个公式:Hi=(H(key)+di) MOD m i=1,2,…,k(k<=m-1)
基本思想:当发生地址冲突时,按照某种方法继续探测哈希表中的其他存储单元,直到找到空位置为止。
(2)链地址法(拉链法)
创建一个链表数组,数组中每一格就是一个链表。若遇到哈希冲突,则将冲突的值加到链表中即可。
java hashmap使用的就是拉链法解决hash碰撞。

觉得不错的,感谢点赞支持!后续再补充一些。

在这里插入图片描述

  • 31
    点赞
  • 146
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
JAVA程序设计专家门诊_11577063-李文泽[高清版,整书签].pdf 出版社: 清华大学出版社; 第1版 (2006年4月1日) 作者:李文泽 丛书名: 专家门诊系列 平装: 465页 语种: 简体中文 开本: 16开 ISBN: 730212485X 条形码: 9787302124856 本书重点介绍了在Java语言的学习过程中所遇到的各种问题,这些问题都是非常基础的,但也是非常重要的,是很多学习Java的人无法从课堂上弄明白的问题。本书按照普通Java教材的顺序循序渐进地回答读者学习过程中经常遇到的问题。使读者不仅知其然,而且还能知其所以然。如果您是第一次学习Java,通过本书就能够全掌握Java。如果您已经学过Java,却仍感到有很多疑问,相信本书能够为您扫清这些阻碍您前进的障碍。   本书的最大特点就是针对每个问题从解题思路,具体步骤,专家指点几个方面进行介绍,让读者在解决一个问题的同时取得举一反三的效果,本书所给出的问题在论坛中也经常出现,都是学习Java的人比较关心的问题,具有很好的参考价值。此外,本书强调理论与实践相结合,注重内容的实用性,提供并详细讲解了大量的程序实例。   本书内容丰富,语言通俗易懂,实用性非常强,适合Java程序设计的初学者,对于有一定经验的Java读者也具有极高的参考价值。本书可作为课堂教学,培训辅导,国际认证考试的教材,也可作为程序开发人员的自学参考书。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值