Java瑣碎知識點

  1. 枚舉類中定義方法
enum S{
    D(1){
        public void f1(){System.out.println("ddd");}
    }
    private int i;
    S(int i){
        this.i = i;
    }
    public void f1(){
        System.out.println("sss");
    }; }

  public static void main(String[] args) {
        S.D.f1();
    }

輸出 ddd,

2.synchronized 和 ReentrantLock
模擬生產者和消費者模式

生產者

import lombok.SneakyThrows;
import java.util.concurrent.TimeUnit;

public class Pro {
    @SneakyThrows
    public void product(){
        System.out.println("生產者在生產。。。");
        TimeUnit.SECONDS.sleep((long)1);
        System.out.println("生產者生產結束");
    }
}

消費者
```java
import lombok.SneakyThrows;
import java.util.concurrent.TimeUnit;

public class Cosu {
    @SneakyThrows
    public void consume(){
        System.out.println("消費者在消費。。。");
        TimeUnit.SECONDS.sleep((long)1);
        System.out.println("消費者消費結束");
    }
}

```java
synchronized版本

        Object lock = new Object();

        //消費者
        new Thread(()->{
            try{
                synchronized (lock){
                    System.out.println("進入消費者");
                    lock.wait();
                    new Cosu().consume();
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

        //確保消費者早於生產者啓動
        TimeUnit.SECONDS.sleep((long)1);

        //生產者生產,生產結束後通知消費者
        new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    synchronized (lock){
                        System.out.println("進入生產者");
                        new Pro().product();
                        lock.notify();
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
ReentrantLock版本
ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();

        new Thread(()->{
            try{
                lock.lock();
                System.out.println("進入消費者");
                condition.await();
                new Cosu().consume();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }).start();

        //確保消費者早於生產者啓動
        TimeUnit.SECONDS.sleep((long)1);

        //生產者生產,生產結束後通知消費者
        new Thread(new Runnable() {
            @Override
            public void run() {
                try{
                    lock.lock();
                    System.out.println("進入生產者");
                    new Pro().product();
                    condition.signalAll();
                } finally{
                    lock.unlock();
                }
            }
        }).start();

3.包權限
【只有】public類對包外可見;
不管父類子類是否在一個包,子類總能訪問父類protected方法;
不同的包下,不能訪問實例的protected方法;
在a包裏的A類中的aa方法不能調用b包下B【實例】的protected方法bb

package com.talent.util;
public class TestProtect {
    protected void p(){}
}
//同一個包下的子類可以訪問
package com.talent.util;
public class TestProtectImpl extends TestProtect{
    protected void pp(){
        p();//在【類】中可以訪問父類protected方法
    }
    public static void main(String[] args) {
        new TestProtectImpl().p();
        new TestProtectImpl().pp();
        new TestProtect().p();
    }
}
//不同包中
package com.talent.user;
import com.talent.util.TestProtect;
import com.talent.util.TestProtectImpl;

public class UserA  {
    protected void proUserA(){
        new TestProtectImpl().pp();//注意,這是不允許的
    }
}
class ImplTestProtectedInAnotherPackage extends TestProtect {
    protected void d(){
        p();//雖然子類和父類不在同一個包,但在【類】中依然可以訪問父類protected方法
    }
}

函数编程

@FunctionalInterface
interface Converter<F, T> {
    //T 是返回值,F是参数
    T convert(F from);
}
class Something {
    String startsWith(String s) {
        return String.valueOf(s.charAt(0));
    }
    
    Integer endWith(String s){
        return Integer.valueOf(s);
    }
    public static void main(String[] args) {
        Something something = new Something();
        Converter<String, String> converter1 = something::startsWith;
        Converter<String,Integer> converter2 = something::endWith;
        String converted = converter1.convert("Java");
        System.out.println(converted);    // "J"
    }
}

常见的函数编程接口

class Person{
    private String firstName;
    private String lastName;
    public Person(String f,String l){
        this.firstName = f;
        this.lastName = l;
    }

    @Override
    public String toString() {
        return "Person{" +
                "firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                '}';
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }


}

class Lambda4 {

    //String代表入参类型,Predicate返回布尔值
    static Predicate<String> isEmpty = String::isEmpty;
    static Predicate<String> isW = s->s.equals("w");

    //泛型参数String代表入参类型,Integer代表返回值类型
    static Function<String, Integer>  toInteger = Integer::valueOf;
    //backToString第一个泛型参数类型 要和toInteger的入参类型一致,andThen中参数类型是toInteger的【返回值】
    static Function<String, String> backToString = toInteger.andThen(integer -> String.valueOf(integer));
    static Function<String,Person> stringToPerson = backToString.andThen(s -> new Person(String.valueOf(s),String.valueOf(s)));
    static Function<String,Person> function1 = s -> Optional.of(new Person(s,s)).get();
    static Function<String,Person> function2 = function1.andThen(person -> person);

    //Person代表入参类型,Consumer没有返回值
    static Consumer<Person> consumer1 = person -> person.getFirstName();
    //consumer2的泛型参数和consumer1的要一致,andThen中的参数是consumer1的【入参】
    static Consumer<Person> consumer2 = consumer1.andThen(s->System.out.println(s));

    static Comparator<Person> comparator = (p1, p2) -> p1.getFirstName().compareTo(p2.getFirstName());


}

finally
finally中的return语句优先级最高;
若try中有return语句,finally中对返回结果进行修改,则修改内容不会返回。

static int tryAndFinally(){
        int a=0;
        try{
            ++a;
            return a;
        }finally {
            a=10;//修改结果不会返回
            System.out.println("finally");
            
        }
    }
    public static void main(String[] args) {
        System.out.println(tryAndFinally());
    }

输入url并回车就是DNS解析和建立tcp连接的过程。

为什么重载equals同时重载hash?
两个Java对象相等,则hash值必须相等;!!!
两个Java对象hash相等,这两个对象可以不相等;
equals比较内容,hash比较是比较本质(比如对象的存储地址,对象的字段等);
如果只重写了equals,那么可能出翔这种情况:
两个对象相等->equals,hash值却不相等

2020-01-23
32、64位系统有什么区别
主要是对寻址能力不同,即对指令的处理速度差异
https://www.cnblogs.com/zhishiyv/p/9683323.html

内存寻址
https://blog.csdn.net/xhumble/article/details/105652695
https://blog.csdn.net/tristacrystal/article/details/84028834

MySQL用B+树不用hash表做索引的原因
hash表不支持范围、模糊;如果hash碰撞很严重,hash表会变成链表

为什么建议使用主键自增的索引?
B+树是有序的,主键是递增的,就不会出现页分裂

如何正确地终止线程
不仅需要调用中断方法,还需要提供中断逻辑,否则,线程不会中断,会继续执行下去。
https://blog.csdn.net/xzp_12345/article/details/81131026

如何解决hash碰撞
1-开放地址法:所有元素会存到开辟的空间
2-链表法:元素会存到联表中,联表头地址存到开辟的空间
https://www.jianshu.com/p/35ece8281890
https://blog.csdn.net/zhuwukai/article/details/77248074
https://blog.csdn.net/qq_35583089/article/details/80048285?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3.not_use_machine_learn_pai&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-3.not_use_machine_learn_pai

HashMap初始大小为什么是16
元素存入hash表中要对表长度取余,16是2的4次方,可以用位运算,加快速度

单链表长度>=8 && 数组总长度>=64(即经过两次扩容),才会把单链表转成红黑树
final void treeifyBin(Node<K,V>[] tab, int hash) {
        int n, index; Node<K,V> e;
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)//64
            resize();

HashMap的put
1-通过hash值计算数组位置,注意这里的hash不是直接调用key.hashCode(),而是使用了HashMap的hash函数

 static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

在HashMap中只要两个键的hash值相同,或者两个键equals,就认为这两个键相同

if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;

2-判断该位置是否有元素,没有就新建一个节点;有就
2-1还是先和第一个比较,hash值一致或者key 相等(equals)就替换
2-2如果该位置是树,则添加树节点
2-3如果第一个没匹配,又不是树,则遍历链表,加到链表末端,或者替换旧值
3-添加之后,判断是否需要扩容

HashMap不安全表现在哪
1-多线程的put可能导致元素的丢失
// 新建节点并追加到链表
if ((e = p.next) == null) { // #1
p.next = newNode(hash, key, value, null); // #2
如果两个线程都走到#1,p.next就会被赋值两次,导致第一次赋值被覆盖
2-put和get并发时,可能导致get为null
如果put后,需要扩容,扩容时会产生一个空数组,如果此时其他线程get,就会得到null值
Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap]; // #1
table = newTab; // #2
ConcurrentHashMap怎么解决线程安全问题呢
1-Node节点中的value用volatile修饰
2-针对HashMap中值覆盖问题采用cas解决
线程1和线程2都走到了#1,假设线程1先赋值,线程2赋值时,发现oldVal变化了就会返回失败

    else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
                if (casTabAt(tab, i, null,
                             new Node<K,V>(hash, key, value, null)))
                    break;                   // no lock when adding to empty bin
            }

3-同步逻辑使用synchronized

在Spring中FactoryBean和BeanFactory有什么区别呢
BeanFactory是IOC容器顶层接口,提供了IOC容器应遵守的的最基本的接口
ApplicationContext就是他的一个实现类
FactoryBean可以通过反射生产Bean
简言之,BeanFactory管理Bean,FactoryBean生产Bean.
https://zhuanlan.zhihu.com/p/124119677
https://www.jianshu.com/p/5ab6643186b3

String和Integer都有缓存,String缓存在常量池,减少了重复对象的创建;
Integer默认缓存-128到127
他们都应该用equals比较,再就是注意equals默认实现是==

怎么解决幻读
MySQL通过MVCC解决了不可重复读;
在MVCC的基础上,手动加锁可以解决幻读。
select for update加排他锁(X锁),其他事物的读写都会被阻塞;select lock in share mode加读共享锁(S锁),其他事务的读不会被阻塞,写会被阻塞。
幻读:
事务A 事务B
select * from user where id= 1;
empty;
insert into user values(1,‘zcx’);

insert into user values(1,‘xxx’);//报重复键

不可重复读是通过读来验证;幻读是通过写来验证;

进程、线程和协程
进程VS线程
1-进程切换更消耗资源
2-多进程程序更健壮(程序中一个进程死了,不会影响其他进程,多线程程序一个进程死了,进程内的所有线程都死了)
3-线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据。
线程和协程
1-线程切换有上下文切换(用户状态和内核状态的切换),协程只有用户状态
2-一个线程内部从结果来看是顺序执行的,协程可以不按照顺序执行,可以“来回执行”
进程通信https://blog.csdn.net/weixin_34135138/article/details/112666445

深拷贝、浅拷贝
浅拷贝:被复制对象的所有值属性都含有与原来对象的相同(这部分是深拷贝),而所有的对象引用属性仍然指向原来的对象(这部分是浅拷贝)。
深拷贝:在浅拷贝的基础上,所有引用其他对象的变量也进行了clone,并指向被复制过的新对象。
@Data
public class Person implements Cloneable {
private String name;
private Integer age;
private Address address;
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj=super.clone();
Address a=((Person)obj).getAddress();
//注意这里,set进去的是拷贝
((Person)obj).setAddress((Address) a.clone());
return obj;
}
}

mysql主从复制如何解决复制延迟问题
造成延迟的原因:
1-从库SQL线程重放是随机写盘的,就是虽然binlog已经同步到从库,但sql线程还没有把数据写入磁盘,即重放不及时。
2-主库高并发,导致sql线程同步不及时
3-重放过程中如果遇到锁等待,也会造成延迟
解决方案
1-从库并行同步(MySQL5.6版本以后)
2-对于实时性要求高的数据,读主库

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值