java面试——java本身基础篇(2022-尊龙官方平台

java面试——java本身基础篇(2022-02-15)

el/2024/3/25 17:20:32

1.equals和==运算符的区别

==运算符说明

对于基本类型和引用类型,==运算符的效果不同,基本的数据类型与基本数据类型的包装体是可以使用==来直接判断值是否相等的,但是包装体与包装体之间的对比不能使用==。

基本类型:比较的是值是否相同 引用类型:比较的是引用是否相同(指向的内存是否一致)

equals说明

equals是objact自带的方法(string与包装体都重写了这个方法),实现了引用类型的值比较

2.hashmap 的实现原理

jdk1.8之前hashmap使用的是【数组 链表】来实现的,实际上是一个“链表散列”的数据结构,即数组和链表的结合体。

向hashmap里put数据时,回根据key来计算hash值,通过hash值得到元素所在数组的下标,若该数组的当前下标已经存放了其他数据,则在这个下标上的数据以链表的形式存放,新加入的在链表的根节点,最先加入的数据放在链表最尾端。如果数组中的当前下标没有数据,则直接将该数据放在数组里。

在jdk1.8开始将hashmap做了优化,改为【数组 链表或红黑树】,当链表中的节点数据超过八个之后,将链表转为红黑树来提高查询效率。

3.hashmap如何扩容

向hashmap里添加元素的时候,会判断当前数组里的元素个数,如果大于等于阈值,则开始扩容。 一般情况,扩容是当前容量的两倍。

  • capacity 即容量,默认16,可以在构造函数里更改。
  • loadfactor 加载因子,默认是0.75,可以在构造函数里更改
  • threshold 阈值。阈值=容量*加载因子。默认12。当元素数量超过阈值时便会触发扩容。

4.如何决定使用hashmap或treemap

hashmap适合插入与删除,treemap适合对于有序的key集合进行排序。

5.hashset的实现原理

hashset不保证排序,允许存放null,不允许由重复的元素。
hashset由hashmap实现,hashset将所有的添加进来的值当作一个key存放在hashmap上,而hashmap的value统一为present(就是一个固定值永远不变)。
hashset的add方法调用的是hashmap的put方法,因此不存在重复元素。关于hashmap如何实现key的不重复,请见本文的第二条。

6.arraylist的实现原理

arraylist的底层使用数组来实现,当向数组添加元素时,都会检查元素个数是否超出数组长度,如果超出则进行扩容,每次扩容是旧数组的1.5倍长度。 arraylist与array之间可以互相转换:

  • list转换成为数组:调用arraylist的toarray方法。
  • 数组转换成为list:调用arrays的aslist方法

7.arraylist 和 linkedlist 的区别是什么

arraylist底层是数组,支持随机方法,时间复杂度是o(1)
linkedlist底层使用【双向循环链表】,不支持随即方法,时间复杂度为o(n)。

8.array与arraylist的区别

  • array可以容纳基本类型与对象,arraylist只能容纳对象
  • array相比arraylist功能较少,没有addall、removeall、iterator等等

9.iterator迭代器是啥

迭代器iterator是一种设计模式,在java里他是一个对象,可以用来遍历并选择序列中的对象。 迭代器是轻量级的对象,创建它的成本很小。 迭代器只能单向移动。

  • hasnext()方法获取是否还有下一个元素,有返回true
  • next()方法获取下一个元素
  • remove()方法将迭代器返回的元素删除

10.iterator与listiterator有什么不同

iterator是java迭代器最简单的实现,为list设计的listiterator有跟多的功能。

  • listiterator可以双向遍历list,也可以从list中插入与删除元素。iterator只能单向遍历。
  • iterator可以用来遍历set、list,listiterator只用于遍历list
  • listiterator实现了iterator接口,并且多了一些功能:添加元素、替换元素、获取前一个和后一个元素的索引等等

11.线程安全的集合

vector

vector是对arraylist线程安全的实现,在实现方式上没有啥区别,arraylist实现方式见本文第六条,vector主要就是加了synchronized关键字。 vector存在的问题:

  • 他的add()、get()方法都会加锁,因此会发生读读互斥
  • 线程a在1下标添加元素,线程b同时在2下标添加元素,也会发成互斥。 因此vector锁的的效率比较低。
hashtable

hashtable是对hashmap线程安全的实现,实现方式上没有区别,hashmap的实现方式见本文第二条,hashtable主要就是加了synchronized关键字。
hashtable与vector存在的问题的问题一致,都是效率比较低

为了解决vector集合和hashtable集合效率低下的问题,我们在选取线程安全的集合时一般会选择copyonwritearraylist集合和concurrenthashmap集合,它的锁的粒度相较于vector和hashtable更小,因此能够高效率的解决vector和hashtable所存在的问题。

concurrenthashmap(线程安全的)的实现原理

concurrenthashmap是java中的一个线程安全且高效的hashmap实现。平时涉及高并发如果要用map结构,那第一时间想到的就是它。
concurrenthashmap与hashmap的底层数据结构一样,都是【数组 链表或红黑树】实现的。 通过cas synchronized关键字保证线程安全,cas可以理解为一个乐观锁

copyonwritearraylist(线程安全的)的实现原理

copyonwritearraylist是arraylist的线程安全版本,与arraylist的底层数据结构一致。是一种读写分离的并发策略,这种容器称为“写时复制器”。
copyonwritearraylist允许并发读(读不上锁)。写操作时会加锁,首先将当前容器复制一份副本,再副本中执行写操作,结束后将原容器的引用指向副本。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wqbiwzwc-1653378963970)(img.png)]
因此copyonwritearraylist适合读多写少的操作,因为每次写入都需要复制一个副本,频繁写操作会频繁的gc回收。

12.并行与并发的区别

  • 并行是指多个事件在同一时间发生,并发是多个事件在同一时间【间隔】发生
  • 并行是在不同实体的多个事件,并发是在同一实体上的多个事件

13.线程与进程

进程是程序运行和资源分配的基本单位,一个程序至少有一个进程,一个进程最少有一个线程。进程拥有独立的内存,不和其他的进程共享内存,而进程下的多个线程,共享内存资源。
线程是进程的一个实体,是cpu调度和分派的基本单位,是比程序更小的能独立运行的基本单位。 同一个进程中的多个线程之间可以【并发】执行

14.java创建进程的三种方式

  • 继承thread类,重写run()方法,调用start()方法就可以启动一个线程。
  • 实现runnable接口,实现run()方法(无返回值),创建runnable接口实现类的实例对象,将其放入thread类的构建方法的入参获取thread实例,调用thread实例的start()方法启动线程。
  • 实现callable接口,实现call()方法(存在返回值),创建callable接口的实现类对象,将其放入futuretask类的构建方法的入参获取futuretask实例,调用futuretask实例的run()方法启动线程。
实现runnable接口案例
class mythread implements runnable {private string name;public mythread(string name) {this.name = name;}@overridepublic void run() {for (int i = 0; i < 200; i) {system.out.println(this.name  "==>"  i);}}
}public class testdemo {public static void main(string[] args) {mythread thread1 = new mythread("threada");mythread thread2 = new mythread("threadb");mythread thread3 = new mythread("threadc");new thread(thread1).start();new thread(thread2).start();new thread(thread3).start();}
}
实现callable接口
public class mycallable implements callable<string> {private int age;public mycallable(int age) {super();this.age = age;}public string call() throws exception {thread.sleep(8000);return "返回值 年龄是:"  age;}}public class run {public static void main(string[] args) throws interruptedexception {try {mycallable callable = new mycallable(100);threadpoolexecutor executor = new threadpoolexecutor(2, 3, 5l,timeunit.seconds, new linkedblockingdeque());//这里使用线程池来运行call()方法里的内容future<string> future = executor.submit(callable);system.out.println("main a "  system.currenttimemillis());system.out.println(future.get());system.out.println("main b "  system.currenttimemillis());} catch (executionexception e) {e.printstacktrace();}}
}

14.runnable与callable的区别

  • runnable的返回值是void,并且重写的是run()方法
  • callable允许有返回值,通过futuretask或future获取返回值,并且重写的是call()方法

15.线程的物种状态

  • 创建状态:创建了线程对象,没有调用start()方法
  • 就绪状态:调用start()方法后,线程调度程序没有将本线程设置为当前运行线程,或在等待、睡眠回来后,均为就绪状态
  • 运行状态:线程调度程序将本线程设置为当前运行线程,开始运行run()方法里的内容
  • 阻塞状态:线程在运行时被暂停,比如运行了seep()、wait()方法
  • 死亡状态:run()方法执行结束或者调用了stop()方法,线程就死亡了,死亡的线程无法再次通过start()方法进入就绪状态

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-phkokk38-1653378963971)(img_1.png)]

16. sleep()和wait()的区别

  • sleep()方法是thread类的静态方法,让线程进入睡眠状态,让出执行机会给其他线程,但是如果在synchronized块中调用sleep()方法,是不会释放资源的,其他线程仍然无法访问。
  • wait()方法是object类的方法,线程运行wait()方法时,该线程进入到一个【和该对象相关的等待池】,并且释放锁,使其他线程能够访问。通过notify()或notifyall()方法唤醒等待的线程。

17.notify()和notifyall()的区别

  • 如果线程调用了某个对象的wait()方法,该线程会进入到【该对象的等待池】里,等待池里的对象不会竞争该对象的锁
  • 有线程调用了对象的notify()方法,则会随机唤醒一个wait线程,调用notifyall()方法则会唤醒所有wait线程。
  • 被唤醒的线程会进入该对象的【锁池】,【锁池】里的线程会取竞争该对象的锁。
  • 优先级高的线程竞争到【对象锁】的改率高,如果线程没有竞争到【对象锁】,则会继续留在【锁池】。如果线程调用wait()方法,则回到【该对象的等待池】里
  • 竞争到【对象锁】的线程会继续执行,运行完synchronized代码块,会释放掉【对象锁】,【锁池】里的线程会继续竞争

18.run()和start()的区别

  • run()方法是线程体,包含了该线程所有需要执行的事情。
  • start()方法是用来启动一个线程的,启动后不一定会立即执行run()方法,需要等待【线程调度程序】将本线程设置为【当前运行线程】时,会执行run()方法

19.创建线程池的四种方式

executors.newfixedthreadpool(int nthreads)

  • 创建一个可以重用固定长度的线程池,提交一个任务创建一个线程,到达最大数量时规模不再变化。当发生未预期的错误导致线程结束,线程池会补充一个新的线程。
  • 使用共享的无界队列方式来运行这些线程,当任务数量大于线程池容量,会存放在一个无边界队列中,等待线程执行。任务不要一口气塞入太多,小心内存溢出。

executors.newcachedthreadpool()

  • 创建一个可缓存的线程池,若线程池的规模超过了处理需求,则回收空闲线程,当需求增加时,自动添加新的线程
  • 对于线程池的规模不做限制

executors.newsinglethreadexecutor()

  • 创建一个单线程的线程池,可以保证任务在队列中按照顺序串行执行
  • 如果这个线程异常结束,会创建一个新线程来代替他

executors.newscheduledthreadpool(int nthreads)

  • 创建一个固定长度的线程池,延迟或定时的方式来执行任务,类似于timer
public class threadpooltest {public static void main(string[] args) {//创建一个可重用,固定线程数的线程池 容量为 2executorservice pool = executors.newfixedthreadpool(2);//创建一个可缓存的线程池,可根据需要创建新线程的线程池.旧的线程可用时将重用他们.对短期异步的程序,可提高程序性能pool = executors.newcachedthreadpool();//创建一个单线程池,只有一个线程,线程任务保证串行运行。可以在旧的线程挂掉之后,重新启动一个新的线程来替代它。pool = executors.newsinglethreadexecutor();//创建一个固定长度的线程池,容量为4,给定一个延迟后,可以运行命令或者定期执行,类似于timerpool = executors.newscheduledthreadpool(4);//线程池添加任务fixeddemo demo = new fixeddemo();fixeddemo demo2 = new fixeddemo();fixeddemo demo3 = new fixeddemo();pool.execute(demo);pool.execute(demo2);pool.execute(demo3);//手动关闭线程池pool.shutdown();}
}class fixeddemo extends thread {@overridepublic void run() {system.out.println("我是一个线程");system.out.println("[currentthread = ]"  thread.currentthread().getname());}
}

20.线程池中submit()execute()方法有啥区别

submit()方法有返回值,可以获取callable接口实现类返回的值。execute()方法无返回值。

21.java程序中如何保证多线程运行安全

  • 原子性:提供互斥访问,保证当前只有一个线程可以对数据进行操作(atomic,synchronized)
  • 可见性:一个线程对内存的修改可以及时的被其他线程看到(synchronized,volatile)
  • 有序性:一个线程观察其他线程中的指令顺序,由于指令重排序,观察结果一般是无序的,使用【happens-before】解决有序性问题

22.什么是死锁,如何防止

死锁是多个进程在运行时,竞争资源或彼此通信,导致的一种阻塞现象,没有外力干涉,则一直阻塞下去。

死锁的必要条件
  • 互斥条件:进程对分配到的资源不允许其他进程访问,其他进程要访问该资源,只能等待占用资源的线程释放后。
  • 请求和保持条件:进程获得一定资源后,又对其他资源发起请求,但是请求的资源被其他线程占用,此时请求阻塞,但又不会释放已占用的资源。
  • 不可剥夺条件:进程获得资源并未使用完毕,不可被剥夺,只能等待该进程使用完毕后释放。
  • 环路等待条件:进程发生死锁后,多个进程之间形成头尾相接的循环等待资源关系。

这四个条件是死锁的必要条件,有一条不满足就不会发生死锁。 有一个特殊情况,使用【lock】上锁,发生了异常,并且没有在finally里进行unlock()释放锁,也会造成死锁。

23.threadlocal是什么,有哪些使用场景

threadlocal用于支持线程局部变量,归属线程自身所有,不在多个线程之间共享。
在管理环境下(比如web服务器),使用线程局部变量要谨慎,在这种环境下,工作线程的生命周期比任何应用变量的生命周期都要长,一旦线程局部变量在工作完成后没有释放,会存在内存泄露的问题。

24.synchronized 底层实现原理

synchronized可以保证方法或者代码块在运行时,同时只能有一个线程进入临界区,还保证了共享变量的【可见性】(本文章的21条有提到) java里的每一个对象都可以作为锁,这是synchronized实现同步的基础

  • 普通同步方法,锁是当前实例对象
  • 静态同步方法,锁是当前的class对象
  • 同步方法块(就是一个代码块),锁是代码块里的对象

25.synchronized 和 lock 有什么区别

  • synchronized是java的保留关键字,lock是一个java类
  • synchronized无法判断是否获取到锁,lock可以判断是否获取到锁
  • synchronized可以自动释放锁,正常执行完成会释放,发生异常导致未正常结束也会释放。lock一定是需要在finally里调用unlock()进行手动释放。
  • synchronized上锁后,其他线程想要获取锁,就必须等待,这个等待是没有时间上限的,lock上锁后,其他线程要获得锁,不一定会一直等待,尝试获取不到锁,线程可以不用一直等待就结束了。
  • synchronized的锁可重入、不可中断、非公平锁,lock锁可重入、可判断、可公平
  • lock适合大量同步的代码时使用,synchronized适合少量同步代码时使用

26.反射是什么

反射是程序可以【访问、检测、修改】本身状态或者行为的能力。对任意一个类,java的反射机制提供如下功能:

  • 运行时判断任意一个对象的所属类
  • 运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具备的成员变量和方法
  • 在运行时调用任意一个对象的方法

27.什么是java序列号,什么情况下需要序列化

为了保存内存中对象的状态(实例变量),并且可以将保存的对象状态再读取出来,java提供了序列化作为尊龙官方平台的解决方案。 以下几种情况适合使用序列化

  • 将内存中的对象保存到文件中或者数据库中
  • 需要将对象通过api接口或者rpc调用传输给其它系统时
  • 通过rmi传输对象时

28.什么是代理模式,动态代理、静态代理又是什么。

为其他对象提供一个代理以控制对某个对象的访问。代理类主要负责为委托了(真实对象)预处理消息、过滤消息、传递消息给委托类,代理类不现实具体服务,而是利用委托类来完成服务,并将执行结果封装处理。
其实就是代理类为被代理类预处理消息、过滤消息并在此之后将消息转发给被代理类,之后还能进行消息的后置处理。代理类和被代理类通常会存在关联关系(即上面提到的持有的被带离对象的引用),代理类本身不实现服务,而是通过调用被代理类中的方法来提供服务。
代理模式可以理解为将真实处理事件的对象封装起来,在外层套一个壳子,为其过滤参数、记录日志、传递参数等等。

  1. 静态代理:创建一个接口,然后创建被代理的类实现该接口并且实现该接口中的抽象方法。之后再创建一个代理类,同时使其也实现这个接口。在代理类中持有一个被代理对象的引用,而后在代理类方法中调用该对象的方法。例如:
//接口
public interface hellointerface {void sayhello();
}//被代理类
public class hello implements hellointerface {@overridepublic void sayhello() {system.out.println("hello zhanghao!");}
}//代理类
public class helloproxy implements hellointerface {private hellointerface hellointerface = new hello();@overridepublic void sayhello() {system.out.println("before invoke sayhello");hellointerface.sayhello();system.out.println("after invoke sayhello");}
}
  1. 动态代理:利用反射机制再运行的时候创建代理类,如果你有多个类需要被代理,并且代理的目的一致,则可以只编写一次代理规则,然后应用在所有的被代理类上,例如:
//接口、被代理类不变,构建一个handler类来实现invocationhandler接口
public class proxyhandler implements invocationhandler {private object object;public proxyhandler(object object) {this.object = object;}@overridepublic object invoke(object proxy, method method, object[] args) throws throwable {system.out.println("before invoke "  method.getname());method.invoke(object, args);system.out.println("after invoke "  method.getname());return null;}
}/**执行动态代理,输出:before invoke sayhellohello zhanghao!after invoke sayhello*/
public class test {public static void main(string[] args) {system.getproperties().setproperty("sun.misc.proxygenerator.savegeneratedfiles", "true");//创建被代理对象hellointerface hello = new hello();//创建动态代理的模板invocationhandler handler = new proxyhandler(hello);//生成代理类的对象,并且调用方法hellointerface proxyhello = (hellointerface) proxy.newproxyinstance(hello.getclass().getclassloader(), hello.getclass().getinterfaces(), handler);proxyhello.sayhello();}
}

29.对象拷贝的方式,为什么要使用对象拷贝

要对某一个对象进行处理,并且还想保留该对象处理之前的状态,则需要使用拷贝,有如下两种方式可以实现拷贝:

  • 实现serializable接口,通过对象的序列化与反序列化实现深拷贝。
  • 实现cloneable接口并重写object类中的clone()方法。

30.深拷贝和浅拷贝

  • 深拷贝:将对象复制一份,两个对象修改其中任意值,另一个的值不会发生改变。
  • 浅拷贝:只是复制了的对象的引用地址,两个对象指向同一个内存地址,两个对象修改其中任意值,另一个的值也会一起改变。

31.throw与throws的区别

throw用于抛出一个异常,throws用于声明这个方法有可能会抛出异常

32.final、finally、finalize的区别

  • final用于修饰变量、方法、类:修饰变量时该变量无法被改变,是一个常量;修饰方法时该方法无法被重写;修饰类时该类无法被继承。
  • finally用于try-catch块里,处理异常的时候,将一定要必须执行的代码放在finally块,一般存放关闭资源的代码,防止内存泄露。
    finalize是一个object类的方法,一般由垃圾回收器来调用。当手动调用system.gc()时,有垃圾回收器调用finalize()来进行垃圾回收。

32.try-catch-finally中哪一个代码块可以被省略?

catch块可以被省略。
严格的说try只是适合处理【运行时异常】,try catch适合处理【运行时异常、一般异常】。即:如果只用try,不加catch,处理【一般异常】是无法编译成功的。
finally在理论上也是可以不写,但是需要进行对资源的释放,防止内存泄露

33.在try-catch-finally中,如果catch中执行return了,finally还会被执行吗?

finally依然会执行,会在return前执行。如果finally块中包含return,则以finally块返回的为准。

public class test{public static void main(string[] args) {/*** 最终输出如下两行* finally执行!* 30*/system.out.println(getint());/*** 最终输出如下两行* finally执行!* 40*/system.out.println(getint2());}public static int getint() {int a = 10;try {system.out.println(a / 0);a = 20;} catch (arithmeticexception e) {a = 30;return a;/** return a 在程序执行到这一步的时候,这里不是return a 而是 return 30;这个返回路径就形成了* 但是呢,它发现后面还有finally,所以继续执行finally的内容,a=40* 再次回到以前的路径,继续走return 30,形成返回路径之后,这里的a就不是a变量了,而是常量30*/} finally {system.out.println("finally执行!");a = 40;}return a;}public static int getint2() {int a = 10;try {system.out.println(a / 0);a = 20;} catch (arithmeticexception e) {a = 30;return a;/** return a 在程序执行到这一步的时候,这里不是return a 而是 return 30;这个返回路径就形成了* 但是呢,它发现后面还有finally,所以继续执行finally的内容,a=40* 再次回到以前的路径,继续走return 30,形成返回路径之后,这里的a就不是a变量了,而是常量30*/} finally {a = 40;return a; //如果这样,就又重新形成了一条返回路径,由于只能通过1个return返回,所以这里直接返回40}}
}

34.常见的异常类

  • nullpointerexception:当应用程序试图访问空对象时,则抛出该异常。
  • sqlexception:提供关于数据库访问错误的异常。
  • indexoutofboundsexception:指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。
  • ioexception:当发生某种i/o异常时,抛出此异常。此类是失败或中断的i/o操作生成的异常的通用类。
  • filenotfoundexception:当试图打开指定路径名表示的文件失败时,抛出此异常。
  • numberformatexception:当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。

35.运行时异常与一般异常的区别

浅的来说【一般异常】是由【非java程序本身】导致的错误,【运行时异常】是【java程序本身】导致的错误。
【io异常、sql处理异常】等属于典型的【一般异常】,比如【空指针异常、数组越界异常】等属于典型的【运行时异常】

下面就会说的深一点:
java由两个错误处理的类error和exception,他们都是throwable的子类。

  • error类:标识jvm检测到的无法预期的错误,属于jvm层次的严重错误,导致jvm无法继续允许了,这种错误无法捕捉到,也无法恢复,只能是打印错误信息,出现了这种错误,只能尽力让java程序安全结束,其他的啥也做不了。
  • exception类:标识可以恢复的意外,是可以捕捉到的,java提供了两个主要的异常【runtime exception 运行时异常】和【checked exception 一般异常】。

checked exception异常(一般异常)java要求我们必须写try-catch处理,否则编译器死给你看。checked exception一般都是外部错误,并不是程序本身的错误,是应用环境中出现的外部错误,例如io错误。

runtime exception异常(运行时异常),我们可以不处理,当出现这类异常,一般都是虚拟机接管,比如常见的空指针异常,一般是程序员的编码逻辑错误。
当出现运行时异常时,java会一直往上抛,直到遇到处理代码,如果没有遇到则分两种情况。如果是多线程由thread.run()抛出,如果单线程由main()抛出。
如果是主线程抛出的,那么这个java程序也就结束了,如果不想这样,那只能是用try-catch包起来。


http://www.ngui.cc/el/5127234.html

相关文章

jmeter:authentication credentials were not provided

jmeter:authentication credentials were not provided 上次在使用jmeter对手机app进行录制后,使用查看结果树对脚本进行回放,出现了{“detail”:“authentication credentials were not provided.”}的问题 上次的链接地址:https…

docker容器内的mysql连接

最近一直在本地虚拟机上学习docker,使用mysql5.5镜像生成容器后,在物理机上使用navicat-premium却无法连接,接下来说下整体过程与解决方法。 1、找到需要下载的mysql镜像 docker search mysql2、下载镜像 docker pull docker.io/mysql3、查…

selenium-xpath使用一个元素定位另一个相关元素

一般的xpath方法就不介绍了。 最近在使用python把excel上的内容自动填写到网页上。并进行一些列的操作。 譬如说下图 每次在新增内容后,需要根据内容的属性(pass,fail等),在点击“小框”勾选,随后进行通过…

【python3】rsa公钥解密

使用python进行公钥加密私钥解密,网上方法很多,这里就不再介绍了。 因公司项目测试需要,要使用rsa公钥加密后的数据请求服务器,服务器使用私钥解密,并将响应使用私钥加密后返回,再使用公钥进行解密…

软件测试测试知识体系

软件测试知识树测试知识体系 为什么要构建测试知识树 对于未入行新人来说:有学习目标,设计入行或转行的学习计划,一目了然的获取学习要点 对于刚入行测试萌新来说:少走弯路,直奔主题,省时 对于测试进阶人…

软件测试职业发展规划(老生常谈的话题,但仍有很多人迷茫)

目标 对于软件测试来说,或者其它任何行业来说,方向很多,路线很多,但是总目标只有一个,认准目标,分解目标,按照计划一步一步踏实走下去,贵在坚持,所以看完以下方向&#…

两张表让你了解软件测试工作流程

一、项目管理流程/软件开发生命周期 输入:客户原始、标书、合同、组织资产、标准、规程、模板 过程产品/pmui研发经理研发测试qa输出立项确定产品基线、调研业务梳理了解项目了解项目、组建团队了解项目了解项目建立基线调研结果需求编制产品原型、需求说明书了解需…

您要的软件测试基础知识思维导图来了

整理的思维导图(具体内容可以关注留言获取):

项目中,你们如何进行需求评审?

开发甲:这个需求咱们能在技术上实现吗?需要的成本、资源是否可支持 开发乙:需求实现方案是否可验证,有没有轻便的实现方案?需求粒度怎么样,对进度、风险评估影响大吗? 测试甲:需求…

测试用例基本概念

01 测试用例的定义 测试用例又叫做test case,是为某个特殊目标而编制的一组测试输入、执行条件以及预期结果,以便测试某个程序路径或核实是否满足某个特定需求。 02 编写测试用例的原因 理清思路,避免遗漏 如果测试的项目庞大而复杂&…
网站地图