Java事务

Spring声明式事务管理默认对非检查型异常进行事务回滚,而对检查型异常则不进行回滚操作。所以必须捕获检查型异常,捕获后再抛出非检查型异常,这样事务方才起效。

https://www.cnblogs.com/savorboard/p/distributed-system-transaction-consistency.html
//TODO

Java线程池

从JDK1.5开始,Java API提供了Executor框架,创建不同的线程池。有单线程池、数目固定的线程池、缓存线程池
Executors线程池工厂提供了一些创建不同特性线程池ThreadPoolExecutor的方法,它们都返回ExecutorService对象:

  • Executors.newSingleThreadPool()
  • Executors.newFixedThreadPool(int size):定长线程池,可控制线程最大并发数,超出的线程在队列中等待。
  • Executors.newCachedTheadPool():适合很多生存期短的任务,空闲线程会在指定时间内被回收。
  • Executors.newScheduledThreadPool():定长线程池,支持定时及周期性任务执行

它们内部都是封装了ThreadPoolExecutor:

ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 15, TimeUnit.SECONDS,new ArrayBlockingQueue(5), new ThreadPoolExecutor.CallerRunsPolicy());

线程池超载后的拒绝策略

池中的线程用光,等待队列也已排满。

扩展线程池

ThreadPoolExecutor提供了用于扩展的接口,比如要监控每个任务执行的开始和结束时间。

打印异常堆栈是排查问题的指南针,用线程池的execte()方法替换submit()方法,可以进而继承ThreadPoolExecutor来扩展出自己的TreaceThreadPoolExecutor。

Guava中扩展的线程池:

  • MoreExecutors.directExecutor() :将任务在调用线程中执行。
  • 将普通线程池转为Daemon线程池。
  • 对Future模式扩展。

估算线程池大小

threadsSize=cpu数量*cpu使用率*(1+等待时间/计算时间)

Fork/Join线程池

分而治之的思想,例如MapReduce,将大任务划分为小任务合成为最终结果。

ForkJoinPool线程池接受提交ForkJoinTask,ForkJoinTask对象可以调用fork()来分叉出小任务。

 

 

Java工具

jps:显示所有java进程

jstack:打印给定java进程的内部线程及堆栈

JMH:Java Microbenchmark Harness,Java微基准测试框架,是在OpenJDK中发布的用于性能测试框架。可以对方法的性能定量分析。

并发

基础概念

并发与并行:并发是串行交替执行,并行就是并行执行。并行只能出现在多核CPU情况下了。但它们的执行结果可能是一致的。并发概念独立于程序语言,多数语言都会涉及到并发问题。 临界区:多线程争用的共享数据。 死锁、饥饿、活锁:死锁是两方都争用;饥饿是一方争用而另一方谦让;活锁是两方都谦让。

并发级别

阻塞无饥饿:公平锁,不论线程优先级别,线程按照顺序排队。 无障碍:非阻塞调度是一种乐观的策略。都无障碍的执行,一旦检测到冲突,立即回滚。 无锁:保证必然有一个线程在有限步内完成。 无等待:要求所有线程都必须在有限步内完成。

锁机制

锁机制有两个层面:一种是代码层次上的,另外一种是数据库层次上的。锁同步更多指的是应用程序的层面,多个线程进来,只能一个一个的访问同一个数据。

数据库锁机制

  • 悲观锁(Pessimistic Locking):独占锁,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制,也只有数据库层提供的锁机制才能真正保证数据访问的排他性。select * from account where name=”Erica” for update 这条 sql 语句锁定了 account 表中所有符合检索条件( name=”Erica” )的记录。

锁优化

  • 减小持有时间
  • 减小粒度:分割数据结构,适用于局部信息调用频繁,全局信息调用不频繁。
  • 锁粗化:把一组连续请求释放锁整合。
  • 读写分离锁:分割功能点,也是减小粒度的一种情况。
  • 锁分离:操作于结构上的位置不同,如take和put操作于LinkedBlockingQueue中链表的首尾。

JVM锁优化

  • 锁偏向:同一线程连续再次申请锁时,无须同步操作。适用于锁竞争少的场景。可以使用虚拟机参数开启锁偏向机制。
  • 轻量级锁:
  • 重量级锁:
  • 自旋锁:
  • 锁消除:通过逃逸分析,去除在没有竞争时使用的锁。可以使用虚拟机参数开启锁消除。

 

Java枚举

在多数其它语言中,枚举只是命令整数常量的列表。在Java中,枚举实际上是类,枚举可以拥有成员变量、成员方法、构造方法。

enum Type{
    A,B,C,D;
}

枚举在编译后,会自动生成一个继承自java.lang.Enum的类。上面的枚举在编译后生成下面的代码:

class Type extends Enum{
    public static final Type A;
    public static final Type B;
    ...
}

更多参考 https://www.cnblogs.com/ldq2016/p/6627542.html

ordinal和value

ordinal()返回的值是索引,value()返回的是给枚举变量赋予的值。

public enum EnumDeviceType {
    Unknow(0),
    MasterSocket(1),
    SlaveSocket(2),
    DoorbellController(42),
    PowerControl(43);

    private int value = 0;

    private EnumDeviceType(int value) {
        this.value = value;
    }

    public int value() {
        return value;
    }

    public static EnumDeviceType valueOf(int value) {
        switch (value) {
            case 0x01:
                return MasterSocket;
        }

        return Unknown;
    }
}

Java集合

并发集合

Java5介绍了并发集合,大部分位于java.util.concurrent并发包中。

  • ConcurrentHashMap
  • CopyOnWriteArrayList:目的是高效并发读取。很多应用场景中,要求读操作尽可能快,写操作可以相对慢。CopyOnWriteArrayList中利用CopyOnWrite机制优化到写入不会阻塞读取
  • ConcurrentLinkedQueue:通过CAS操作和锁分离,是高并发环境中性能最好的队列。
  • BlockingQueue:线程间数据共享阻塞队列接口,它有不同的实现。BlockingQueue让从队列中获取消息的服务线程在队列空时等待,当有消息后再将线程唤醒。主要操作它的put和take方法。
  • ConcurrentSkipListMap:随机数据结构,跳表。跳表的内部维护了分层的多个链表,使用锁分离机制,查询时间复杂度是O(lgn)。

ConcurrentHashMap

ConcurrentHashMap,不仅提供线程安全,还用锁分离和内部分区等现代技术提高了可扩展性。把实际map分割(segmentation)成若干部分,默认值为16,使的多线程减小争用。但其size()等方法可能需要全局锁而取得所有段的锁,性能反而比HashMap低。

(低并发)线程安全容器:

  • Collections.synchronizedMap()
  • Collections.synchronizedList()
  • Vector
  • Hashtable:大小增加到一定的时候,性能会急剧下降,因为迭代时整个map需要被锁定很长的时间。

BlockingQueue

ArrayBlockingQueue

LinkedBlockingQueue:通过takeLock、putLock两把锁实现了读数据和写数据的分离,实现了对独占锁分离。

 

PriorityQueue 保证最高或者最低优先级的的元素总是在队列头部,当遍历一个 PriorityQueue 时,没有任何顺序保证。
LinkedHashMap 维持的顺序是元素插入的顺序。LinkedHashMap 课保证遍历顺序是元素插入的顺序。
集合的排序:可以使用有序集合,如 TreeSet 或 TreeMap,或者使用有顺序的的集合,如List,然后通过 Collections.sort() 来排序。
打印数组:数组没有实现 toString() 方法,可以使用 Arrays.toString() 和 Arrays.deepToString() 方法来转为字符串再打印数组。
Java 中的 LinkedList 是单向链表还是双向链表。在 Eclipse,可以使用快捷键 Ctrl + T,直接在编辑器中打开该类检查源码。
Java 中的 TreeMap 是使用红黑树实现的。
在 Java 7 中,ArrayList 的默认大小是 10 个元素。Java 7 中 ArrayList 和 HashMap 类的代码片段:

// from ArrayList.java JDK 1.7
private static final int DEFAULT_CAPACITY = 10;

//from HashMap.java JDK 7
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

遍历 ArrayList 时移除一个元素,不是使用ArrayList 的 remove() ,而是使用Iterator 的 remove()方法,则不会出现 ConcurrentModificationException 异常。
想使用 Java 中增强的for-each 循环来遍历,只需要实现 Iterable 接口。或者实现 Collection 接口,默认就具有该属性。
Vector、Hashtable等是同步集合类,用同步方法来实现了线程安全, 而ArrayList、HashMap等不是线程安全的。

Java集合继承结构
集合继承结构

HashMap

由数组加链表实现

默认大小是16个元素(必须是2的幂),因为可以通过按位与计算余数,比求模更快。

Hashtable 与 HashMap

a) Hashtable 是 JDK 1 遗留下来的类,而 HashMap 是后来增加的。
b)Hashtable 是同步的,比较慢,但 HashMap 没有同步策略,所以会更快。
c)Hashtable 不允许有个空的 key,但是 HashMap 允许出现一个 null key。
大多数情况下,只要不涉及线程安全问题,Map基本都可以使用HashMap。HashMap的是无序的,允许将null用作键和值,非线程安全。HashMap不能保证元素的顺序,HashMap能够将键设为null,也可以将值设为null。
Hashtable,(注意大小写:不是HashTable),Hashtable不能将键和值设为null,否则运行时会报空指针异常错误,Hashtable是线程安全的。
HashSet 的内部采用 HashMap来实现。HashSet 允许有一个null key。

LinkedHashMap

LinkedHashMap增加了时间和空间上的开销,通过维护一个运行于所有条目的双向链表,LinkedHashMap保证了元素迭代的顺序。该迭代顺序可以是插入顺序或者是访问顺序。LinkedHashMap是有序、Key和Value都允许空、非线程安全的。LinkedHashMap可以认为是HashMap+LinkedList,即它既使用HashMap操作数据结构,又使用LinkedList维护插入元素的先后顺序。LinkedList每次访问一个元素(get或put),被访问的元素都会被提到最后面。
LinkedHashMap可以应用来实现LRUCache,LRU即Least Recently Used 最近最少使用。当缓存满了,优先淘汰最不常访问的数据。

LinkedHashMap相关问题:
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to xxx。
rpc远程调用在底层还是使用的HTTPClient,所以在传递参数的时候,必定要有个顺序,不然服务层在接的时候就出问题了,所以它才会转为LinkedHashMap。spring 有一个类叫ModelMap,继承了linkedhashMap,即 public class ModelMap extends LinkedHashMap,所以一个接口返回的结果就可以直接用ModelMap来接。注意ModelMap是没有泛型的,不管返回的结果是什么类型的map,泛型是多复杂的map,都可以直接new一个Modelmap,用它来接返回的结果。

Java 中使用 Collections 的最佳实践

a)使用正确的集合类。如果不需要同步列表,使用 ArrayList 而不是 Vector。
b)优先使用并发集合。不是对集合进行同步并,发集合提供更好的可扩展性。
c)使用接口表示和访问集合。如使用List存储 ArrayList,使用 Map 存储 HashMap 。
d)使用集合的时候使用泛型。
e)使用迭代器来循环集合。

线程安全的集合

喂,SHE
喂(V,Vector)
S(Stack)
H(Hashtable)
E(Enumeration)

生产者消费者模型

在现实中许多线程问题都属于生产者消费者模型。较低级的解决方式是用wait和notify,更好的办法是用Semaphore 或者 BlockingQueue

生产者消费者模型,准确地说应该是“生产者-消费者-仓储”模型,有以下几点需要明确:
1、生产者仅仅在仓储未满时候生产,仓满则停止生产。
2、消费者仅仅在仓储有产品时候才能消费,仓空则等待。
3、当消费者发现仓储没产品可消费时候会通知生产者生产。
4、生产者在生产出可消费产品时候,应该通知等待的消费者去消费。

生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品。解决生产者/消费者问题的常用方法是采用某种机制保护生产者和消费者之间的同步,常用的同步方法是采用信号或加锁机制,保证资源在任意时刻至多被一个线程访问。

如下代码示例,使用了BlockingQueue阻塞队列来线程间共享数据:

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * java多线程模拟生产者消费者问题
 * 
 * ProducerConsumerApplication是主类,Producer生产者,Consumer消费者,Product产品,Storage仓库
 */
public class ProducerConsumerApplication {
    public static void main(String[] args) {
        ProducerConsumerApplication pc = new ProducerConsumerApplication();
        Storage s = pc.new Storage();
        Producer p1 = pc.new Producer("生产者1", s);
        Producer p2 = pc.new Producer("生产者2", s);
        Consumer c1 = pc.new Consumer("消费者1", s);
        Consumer c2 = pc.new Consumer("消费者2", s);
        Consumer c3 = pc.new Consumer("消费者3", s);

        ExecutorService service = Executors.newCachedThreadPool();
        service.submit(p1);
        service.submit(p2);
        service.submit(c1);
        service.submit(c2);
        service.submit(c3);
    }

    /**
     * 消费者
     */
    class Consumer implements Runnable {
        private String name;
        private Storage s = null;

        public Consumer(String name, Storage s) {
            this.name = name;
            this.s = s;
        }

        public void run() {
            try {
                while (true) {
                    System.out.println(name + "准备消费产品.");
                    Product product = s.pop();
                    System.out.println(name + "已消费(" + product.toString() + ").");
                    Thread.sleep(500);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 生产者
     */
    class Producer implements Runnable {
        private String name;
        private Storage s = null;

        public Producer(String name, Storage s) {
            this.name = name;
            this.s = s;
        }

        public void run() {
            try {
                while (true) {
                    Product product = new Product((int) (Math.random() * 10000)); // 产生0~9999随机整数
                    System.out.println(name + "准备生产(" + product.toString() + ").");
                    s.push(product);
                    System.out.println(name + "已生产(" + product.toString() + ").");
                    Thread.sleep(500);
                }
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }
    }

    /**
     * 仓库,用来存放产品
     */
    public class Storage {
        BlockingQueue queues = new LinkedBlockingQueue(10);

        /**
         * 生产
         */
        public void push(Product p) throws InterruptedException {
            queues.put(p);
        }

        /**
         * 消费
         */
        public Product pop() throws InterruptedException {
            return queues.take();
        }
    }

    /**
     * 产品
     */
    public class Product {
        private int id;

        public Product(int id) {
            this.id = id;
        }

        public String toString() {
            // 重写toString方法
            return "产品:" + this.id;
        }
    }
}

数组转List

List list=java.util.Arrays.asList(arr);

Java开发库

Guava

Guava是一种基于开源的Java库,其中包含谷歌正在由他们很多项目使用的很多核心库。这个库是为了方便编码,并减少编码错误。这个库提供用于集合,缓存,支持原语,并发性,常见注解,字符串处理,I/O和验证的实用方法。

NTP

SNTP是简单网络时间协议(Simple Network Time protocol)的简称,它是目前Internet网上实现时间同步的一种重要工程化方法。
SNTP协议采用客户/服务器工作方式,服务器通过接收GPS信号或自带的原子钟作为系统的时间基准,客户机通过定期访问服务器提供的时间服务获得准确的时间信息,并调整自己的系统时钟,达到网络时间同步的目的。客户和服务器通讯采用UDP协议,端口为123。

验证ntp服务:ntpq -p
查看当前时间:date -R

查找当前地区最适合的时间服务器:打开网站 http://www.pool.ntp.org/zone/asia,会在页面上部推荐一组最合适的同步服务器。在配置ntp服务时可以把它们复制粘贴到etc/ntp.conf中。

对时请求时设置超时时间在1秒内,超时即对时不成功,保证时间精度。
https://blog.csdn.net/hexiangqwqwqw/article/details/49801573
CentOS下NTP时间服务器搭建
http://blog.51cto.com/superpcm/2089888
Centos7配置ntp时间服务器
https://blog.csdn.net/zzy5066/article/details/79036674
docker 搭建ntp服务器
https://www.cnblogs.com/liubin0509/p/6282858.html

java实现NTP客户端

添加依赖commons-net

<!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
<dependency>
    <groupId>commons-net</groupId>
    <artifactId>commons-net</artifactId>
    <version>3.6</version>
</dependency>

获取时间

String getDateTime(){
        try {
            NTPUDPClient timeClient = new NTPUDPClient();
            InetAddress timeServerAddress = InetAddress.getByName("cn.pool.ntp.org");
            TimeInfo timeInfo = timeClient.getTime(timeServerAddress);
            TimeStamp timeStamp = timeInfo.getMessage().getTransmitTimeStamp();
            DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return dateFormat.format(timeStamp.getDate());
        } catch (UnknownHostException e) {
            e.printStackTrace();
            System.out.println("与ntp服务器同步时间错误!");
            return dateFormat.format(new Date());
        } catch (IOException e) {
            System.out.println("与ntp服务器同步时间错误!");
            return dateFormat.format(new Date());
        }
    }

Java基础

命令行运行java

jar包都放在lib文件夹里

java -Djava.ext.dirs=lib Main

参数前加-D,用来在启动一个java程序时设置系统属性值。如果该值是一个字符串且包含空格,那么需要包在一对双引号中。
系统属性值是可以通过System.getProperty()得到的系统属性。

#将所有的调试信息输入到文件 nohup.out
nohup java -jar vPaas.jar > nohup.out 2>&1 &

运行参数和系统参数
Springboot项目java -jar 启动jar包参数详解
https://blog.csdn.net/baidu_35140444/article/details/82980139

ubuntu 安装jdk

JDK是java的开发环境,它包括了运行环境(jre)和开发中需要的编译、调试、程序诊断。
很多软件已不需要通过环境变量JAVA_HOME来找到java的运行环境。
http://www.cnblogs.com/a2211009/p/4265225.html

jre是提供java运行环境而不是开发环境
OpenJDK 和 Sun JDK 的关系

sudo apt-get install openjdk-8-jdk

Centos安装OpenJDK

#yum搜索OpenJDK8软件包 
yum search java-1.8.0|grep openjdk 
#安装java-1.8.0-openjdk.i686
yum install java-1.8.0-openjdk.x86_64 -y 

Map和List的简单构建方式

new HashMap(){{
            put("saleState",saleState);
            put("serveType",serveType);
        }}

new ArrayList<List>(){{
add(masterSocketDeviceIds);
add(dimmingLightDeviceIds);

Array转List
List list= Arrays.asList(strArr);
}};

Java没有范型数组

java中的数据类型分类

  • 基本数据类型(或叫做原生类、内置类型)8种:
    整数:byte,short,int,long(默认是int类型)
    浮点类型: float,double(默认是double类型)
    字符类型:char
    布尔类型:boolean,布尔类型数据只有两个值:true(真)、false(假),不对应任何数字,不能与数字进行转换。
    数据类型之间除了boolean,其他数据类型之间可以任意的相互转换(强制转化或默认转换),这个与c++中有区别。
  • 引用数据类型
    3种:类、接口、数组。数组不是原生类,数组是一种对象。java中定义数组有两种方式,一种是int[] number,另一种是int number[]。推荐第一种,可读性高。

byte

char与byte?
byte是8位的一个字节。
char通常以UTF-16 Big Endian的方式保存一个UNICOEDE字符,是16位的整数。

java中的byte、int等都是有符号的,取byte的无符号数只要进行&0xff操作即可:

public static int[] toUbytes(byte[] bytes){
        int[] ints=new int[bytes.length];
        for(int i=0;i<bytes.length;i++){
            ints[i] = bytes[i] & 0xff;
        }
        return ints;
    }

public static String bytes2HexString(byte[] bytes) {
        String ret="";
        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            ret+=hex;
        }

        return ret.toUpperCase();
    }

Java字段反射+POI示例:
http://blog.csdn.net/panpan96/article/details/76566475

不可变(immutable)对象

Integer,String。

Base64

BASE64Encoder/BASE64Decoder类在sun.misc包中,是sun公司的内部方法,以后有删除的潜在可能,
Base64类在java.util包中,推荐使用Base64.getEncoder()。

split

String[] subs=str.split(“,”,-1);//limit -1 不忽略两端的分隔符。

java -jar 命令行传参并获取的方法

方式一:
java -jar xxx.jar aaa bbb cccc,传了3个参数,通过main方法的参数获取。
方式二:
java -jar xxx.jar -Da1=aaa -Db1=bbb -Dc1=ccc,通过System.getProperty(“aaa”,”1″); 方式获取。作为环境变量。
方式三:
java -jar xxx.jar –a1=aaa –b1=bbb,springboot的写法,可以通过@Value(“${a1}”)获取。
注意参数的位置以及中划线符号的数目:
jar、Dspring.profiles.active前面是一个中划线,db.url等自定义参数前面是2个中划线。
-Dspring.profiles.active位于-jar之前,–db.url参数位于.jar之后。

java -Dspring.profiles.active=dev -jar yirui_clock_storage-1.0.jar --db.url=localhost --db.port=14000 --db.username=数据库用户名 --db.password=数据库密码

spring.profiles.active运行时指定方式

mvn命令运行:mvn spring-boot:run -Drun.profiles=test
命令行运行jar文件: java -jar -Dspring.profiles.active=test xxx.jar

Java对象的地址

对象的hashcode是否是它的地址,这取决于具体的实现,一般来说,它常常是对象的初始地址的整数表示,但是这种实现技术并不是Java编程语言所规定的。在GC后,对象的地址可能会变动,不同的JVM实现也有差异。

java知识网站

http://www.java1234.com

Java的参数传递都是值传递

传值分为内容值和地址值,传地址值可以认为是传引用。

  • 值传递:方法调用时,实际参数把它的值的副本传递给对应的形式参数。特点:此时内存中存在两个相等的基本类型,即实际参数和形式参数,后面方法中的操作都是对形参这个值的修改,不影响实际参数的值。
  • 引用传递:方法调用时,实际参数的地址的副本被传递给方法中相对应的形式参数,函数接收的是原始值的内存地址。在方法执行中,形参和实参内容相同,指向同一块内存地址,方法执行中对引用的操作将会影响到原始对象。但对引用的赋值不会影响原始对象。
  • 基本类型:传递的是值的拷贝,也就是说传递后就互不相关了,也就是说,不过副函数的副本如何变化,主本永远不会被影响。
  • 引用类型:传递的是引用地址值,有可能会被影响。
  • String:传引用,但由于String不可变性,传递后不相关。

String

String是final修饰的java类,不是基本的数据类型。
String、StringBuffer、StringBuilder三者中,StringBuffer运行速度比String快,StringBuilder运行速度最快。StringBuffer是线程安全的,String的值是不可变的。
andyweike博客之String

String s = new String(“xyz”);创建了几个String Object?答案:两个。一个是字符串字面量”xyz”所对应的、驻留(intern)在一个全局共享的字符串常量池中的实例,另一个是通过new String(String)创建并初始化的、内容与”xyz”相同的实例。

String是immutable的,其内容一旦创建好之后,就不可以发生改变。StringBuffer 改变的原理是其内部采用了字符数组存放数据。

substring(start,end)取头去尾

IO 的最佳实践

a)使用有缓冲区的 IO 类,而不要单独读取字节或字符。
b)使用 NIO 和 NIO2
c)在 finally 块中关闭流,或者使用 try-with-resource(Java7) 语句。
d)使用内存映射文件获取更快的 IO。

管道(Pipe)通信中性质?
A、进程对管道进行读操作和写操作都可能被阻塞,管道为空,读操作会被阻塞;管道满了,写操作会被阻塞。
B、一个管道可以有多个进程对其读;也可以有多个进程写,只不过不能同时写。
C、匿名管道只能单向;命名管道可以双向。
D、管道的容量仅内存大小限制

Object类

  • wait, notify 和 notifyAll 方法定义在Object类中。
  • filalize定义在Object类中,它只有在对象被GC时才会被调用,可以在这个方法里释放掉非Java代码开辟的内存空间。

内部类

A、 内部类的名称与定义它的类的名称不可以相同
B、 内部类可用abstract修饰
C、 内部类可作为其他类的成员
D、 内部类可访问它所在类的成员

运算符

运算符优先级口诀:单算位关逻三赋。
单目:++、–
算术:+、-、*、/、%
位:位移运算符:>、>>>
关系:、=、==
逻辑:&&、||、!、&、|、^
三目:三目运算符(又称为三元运算符)A>B? x:y
赋值:=

java中的i++和++i在java语言层面上来看,使用中间量机制:i=i++,i不变; i=++i相当于++i;但结合在一个语句里使用则会报错,因为++后应该跟变量。同理,i=(++i)++也是不对的。

执行顺序

try中有return语句,finally块会执行完后再去执行return。

final用于声明属性、方法和类,分别表示属性不可变、方法不可覆盖、类不可继承。
finalize是Object类的一个方法,在垃圾收集器执行的时候,会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源的回收,例如关闭文件等。一个对象只能执行一次finallize,只能在第一次进入被回收的队列,而且对象所属于的类重写了finalize方法时,才会被执行。第二次进入回收队列的时候,不会再执行其finalize方法,而是直接被二次标记,在下一次GC的时候被GC。一个对象可能多次进入回收队列?

finally也有不执行的时候,但是这个题不要扣字眼。
**1. 在try中调用System.exit(0),强制退出了程序,finally块不执行。**
**2. 在进入try块前,出现了异常,finally块不执行。**

编译时异常和运行时异常

编译时异常在编码中必须要捕获,而运行时异常可以通过优化完善代码而解决。
RuntimeException和Error都是运行时异常,也称为非检查型异常,运行时异常编码捕获为可选。