点点滴滴d

  •  问题: 如果一个类,继承一个类 、实现多个接口后,该类的对象强转?

@Test
public void testABC(){
   // 原始类
   ABClass abClass = new ABClass();

   // 原始类可强转为任意父类或接口。强转后,只能访问父类或接口的 api
   AInterface aInterface = (AInterface)abClass;
   aInterface.ma(); // 只能访问 AInterface 接口的 ma方法
   BInterface bInterface = (BInterface)abClass;
   bInterface.mb(); // 只能访问 BInterface 接口的 mb方法
   CClass cClass = (CClass)abClass;
   cClass.mc(); // 只能访问 CClass 接口的 mc方法

   // 强转为某一个接口或者父类后,还可以强转为其他类型
   BInterface azb = (BInterface) aInterface;
   azb.mb();
   CClass bzc = (CClass) azb;
   bzc.mc();
   AInterface cza = (AInterface) bzc;
   cza.ma();


}
interface AInterface{
   void ma();
}
interface  BInterface{
   void mb();
}
abstract class CClass{
   protected void mc(){};
}
class ABClass extends CClass implements AInterface,BInterface{
   @Override
   public void ma() {
   }
   @Override
   public void mb() {
   }
}

ABClass 继承了 CClass 并 实现了 AInterface和BInterface,

此时,ABclass实例对象可以强转为任意类型。 

  • 抽象类 实现接口时,可以不用实现 接口中的 api

abstract class ABStractClass implements AInterface{

}
  • 二进制位

四种组合
00

01

10

11

三种 按位 逻辑运算:

按位 与     &  : 11  =》 1   

按位 或      |  :01/ 10/ 11 =》1

按位 异或  ^ :01/ 10 =》 1

或 |  包含 异或 ^

异或^  是 或|  的 2种情况

因为  或|  运算 得到了 1,无法推断出 是 都为1 还是 有 0 和 1

所以,通过 异或^ 得到了1,推断的肯定是 0和1

异或 能判断出 两个值 是否相同

0^0=0

1^1=0

0^1=1

1^0=1

一个值 与 自身 异或运算,总是位 false  0

x^x=0

一个值 与 0 异或运算,还是本身

x^0=x

异或运算 可交换

x^y=y^x

异或运算 可结合

x^(y^z)=(x^y)^z

static final int tableSizeFor(int cap) {
        int n = cap - 1;
        n |= n >>> 1;
        n |= n >>> 2;
        n |= n >>> 4;
        n |= n >>> 8;
        n |= n >>> 16;
        return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
    }

HashMap的这个方法,即用到了 位移,也用到了逻辑或运算。

表达的意思为:

将数据的最高1为与最高2位进行或

然后将最高1和2与最高3和4进行或

直到 将32位的整数,前16位与后16位进行或运算,以保证 所得的数据位 2的倍数

首位符号位:0 正数、1负数

以补码表示:补码=反码(原码除符号位按位取反)+1

负数补码一般都是:

1111xxx (数字的二进制取反+1)

如:

-2

1111 1110

2^n -1  表示 n 个 1,也就是 2的n次方 -1 的值,用二进制表示为 n个1

  • 打印几个“a:”

public void test_(){
   a:
   for (int i=0;i<10;i++){
      System.out.println("a:" + i);
      for (int j=0;j<5;j++){
         System.out.println("b"+j);
         if (j==2){
            break a;
         }
      }
   }
}

a:0
b0
b1
b2
 

内层break 结束了整个循环

  • 什么时候会出现哈希碰撞

HashMap 在计算 key 的hash值的方法中:

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

可以看到,

如果key为null,则hash为0

否则,调用key的 hashCode 方法。

hashCode方法是Object的方法,是一个本地方法。也可以进行重写,重写的hashCode返回的hash值 很容易相同。这个时候就可能出现哈希碰撞了。

public native int hashCode();

如果发生了哈希碰撞,则会将元素放在该链表最后,如果链表过长,则转为红黑树。(what is 红黑树?)

  • 关于环境变量

学java最开始的是配置环境变量,java中的环境变量需要配置两个:1 、path ; 2、classpath

1. path: 这个环境变量中配置的都是操作系统的可执行文件,也是我们执行 某一命令时,如 java -version ,操作系统 需要根据path配置的路径里去寻找这个命令所对应的可执行文件。

2. classpath:这个环境变量 是转属于 java的变量,java 在加载 类时,需要根据 classpath配置的路径中去加载所需要的类。

有一个问题,java是怎么使用这个classpath的呢?如何获取classpath环境变量配置的值呢?

java中有一个System 类,该类中提供了一个静态方法,Map<String,String> getenv(),只要调用 System.getenv();即可获取到当前操作系统所有的环境变量配置。按需获取就行了。 

  • 加载资源

java中加载资源,一般都是用ClassLoader.getResource(String path); 来加载的,这里的 path 需要注意的是,当前应用的 classpath,也就是说,如果你想加载一个静态资源,那么需要把他放在classpath下才行。

  • xml疑惑解答

XSD文件:

<xsd:schema   // 开头都是这样的

xmlns="http://www.springframework.org/schema/context"  // 该xsd名称空间

xmlns:xsd="http://www.w3.org/2001/XMLSchema"  //  都需要引入:该XSD需要遵守的规范

xmlns:beans="http://www.springframework.org/schema/beans"  // 引用了其他的XSD

xmlns:tool="http://www.springframework.org/schema/tool"  // 引用的其他的XSD

targetNamespace="http://www.springframework.org/schema/context"  // 该xsd的名称空间

elementFormDefault="qualified"  // 该名称空间的,默认是这个值

attributeFormDefault="unqualified"> //该名称空间的,默认是这个值

<xsd:import namespace="http://www.springframework.org/schema/beans" schemaLocation="https://www.springframework.org/schema/beans/spring-beans-4.3.xsd"/> // 因为上述引用了其他的XSD,所以这里需要import 其位置

<xsd:import namespace="http://www.springframework.org/schema/tool" schemaLocation="https://www.springframework.org/schema/tool/spring-tool-4.3.xsd"/>  // 因为上述引用了其他的XSD,所以这里需要import 其位置

示例:

<xsd:schema

xmlns="http://www.wxj.org/schema/test"  // 自己定义的

xmlns:xsd="http://www.w3.org/2001/XMLSchema" 

targetNamespace="http://www.wxj.org/schema/test" 

elementFormDefault="qualified" 

/>

XML:

<xmlns="http://www.wxj.org/schema/test"   //默认名称空间

xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance" // 默认需要引入

xmlns:tt="http://www.wxj.org/schema/test" // 其他的名称空间, tt 是别名

xsi:schemaLocation=" http://www.wxj.org/schema/tes  http://www.wxj.org/schema/tes/test.xsd" // 指定其位置
>
  • Spring和mybits解析xml

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance()
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = builder.parse(inputSource);

都是用的saxp

  • 代理

查看生产代理的方式:

System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");  // jdk

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\");//cglib  

//或者jdk 可以自己输出:

byte[] proxyClassFile = ProxyGenerator.generateProxyClass("aaaa", new Class[]{IJdkProx.class});
File file = new File("D:\\code\\aaaa.class");
file.createNewFile();
FileOutputStream fileOutputStream = new FileOutputStream(file);
fileOutputStream.write(proxyClassFile);

// JDK 代理 

package com.wxj;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

final class $Proxy0 extends Proxy
  implements IJdkProx
{
  private static Method m1;
  private static Method m3;
  private static Method m2;
  private static Method m0;

  public $Proxy0(InvocationHandler paramInvocationHandler)
    throws 
  {
    super(paramInvocationHandler);
  }

  public final boolean equals(Object paramObject)
    throws 
  {
    try
    {

     // this.h  就是 构造方法传入的 paramInvocationHandler
      return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final void fun()
    throws 
  {
    try
    {
      this.h.invoke(this, m3, null);
      return;
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final String toString()
    throws 
  {
    try
    {
      return ((String)this.h.invoke(this, m2, null));
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  public final int hashCode()
    throws 
  {
    try
    {
      return ((Integer)this.h.invoke(this, m0, null)).intValue();
    }
    catch (RuntimeException localRuntimeException)
    {
      throw localRuntimeException;
    }
    catch (Throwable localThrowable)
    {
      throw new UndeclaredThrowableException(localThrowable);
    }
  }

  static
  {
    try
    {
      m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
      m3 = Class.forName("com.wxj.IJdkProx").getMethod("fun", new Class[0]);
      m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
      m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
      return;
    }
    catch (NoSuchMethodException localNoSuchMethodException)
    {
      throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
    }
    catch (ClassNotFoundException localClassNotFoundException)
    {
      throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
    }
  }
}

// cglib

反编译打不开,使用javap 查看

会重写 toString,equals,hashCode,clone方法,

及会重写 父类方法。

方法逻辑:

调用   net.sf.cglib.proxy.MethodInterceptor#intercept(代理对象this, 重写的方法Method对象,方法参数,MethodProxy对象) 方法

  • 实现接口方法的一种方式

A extends B implements C

A 实现接口C,

但C中的方法在B中被实现

比如:

Implements method in org.springframework.beans.factory.config.ConfigurableBeanFactory via sub-class org.springframework.beans.factory.support.AbstractBeanFactory 

DefaultSingletonBeanRegistry#registerDependentBean 方法 就是 它的子类 实现了接口的方法

比如:

Ainterface 接口中有一个 m1方法

BClass 类中也有一个 m1 方法

此时,Ainterface 与BClass 是没有关系的,只是他们有个方法签名是相同的

CClass 继承了BClass 类,实现了 Ainterface,这时, CClass 应该实现Ainterface接口的m1方法。

但是,CClass类 可以不用实现m1方法,而是通过继承BClass 的m1方法。

因此,BClass  的 m1 方法,有一个 上下双向的 红色箭头,就表示 有子类CClass 继承了BClass ,并且 子类CClass需要实现的接口Ainterface里 有 m1方法。这个时候 子类就可以 不用 实现 m1方法,直接用了 BClass的m1方法。这也是 继承的一个特性吧,子类继承父类的所有方法。

  • 实例化类

通常示例化一个类,都是用 new 关键字。

通常,在中间件的 框架 组件中,实例化类 经常用的是 反射,也就是 先拿到 Class对象,然后在获取到 构造方法,再实例化类。

拿到Class对象的 一种方式就是 使用 JDK 提供的 Class 类的 静态方法:

java.lang.Class#forName(java.lang.String)

java.lang.Class#forName(java.lang.String, boolean, java.lang.ClassLoader)

需要提供一个 String类型的参数,也就是像这样的:"com.wxj.test.A"

注解

spring处理注解,可以看:

org.springframework.core.annotation.AnnotationTypeMapping 这个类

        // 通过 Class对象 可以获取当前类的 注解
        // 返回的 注解实际上是一个 代理类对象
        Annotation[] annotations = CA.class.getAnnotations();

        // Annotation 这是一个 注解的代理对象
        Annotation annotationProxy = annotations[0];

        // 这才是 注解的 Class 对象, 获取到这个对象后,就可以 使用 Class 对象的一些方法了
        Class<? extends Annotation> annotationClass = annotationProxy.annotationType();

        // 比如: 获取当前注解上的注解
        Annotation[] declaredAnnotations = annotationClass.getDeclaredAnnotations();

        // 很多情况下,尤其是再 spring 框架中,都会注解上嵌套注解,嵌套又嵌套,最后搞晕了
        // 实际就是 利用这种方式来获取 当前类上 的所有注解,
        // 不论是直接声明的,还是 嵌套的
        // 只要有这个注解,就可以进行 相应的处理逻辑了。
        // 只不过spring封装的比较好,不容易找到对应的代码在那里,
        // 通过断点,找到了: org.springframework.core.annotation.AnnotationsScanner.getDeclaredAnnotations

        // 直接判断 当前类是否含有注解
        boolean annotationPresent = CA.class.isAnnotationPresent(A1.class);

        // 获取类的所有注解
        Annotation[] declaredAnnotations1 = CA.class.getDeclaredAnnotations();

        // 直接获取 类上 的 某个注解
        A1 declaredAnnotation = CA.class.getDeclaredAnnotation(A1.class);

属性字段是否可以用is开头

因为常用的 lombok 的 @Data注解,

针对使用 @Data注解的情况下:

对于boolean类型的字段:

1. 如果不用is开头

获取:isXxx

赋值:setXxx

2. 如果用is开头

获取:isXxx

赋值:setXxx

也就是说,不论是否用 is 开头,自动解析生成的属性方法 和 不带  is  的是一样的。

再反过来推 字段,就不确定 本来是 带 is 还是 不带 is, 字段名就无法确定。

结论: 最好不要用 is 开头

对于非 boolean类型的属性,没有这种问题。

String 为空的 2 个方法

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.9</version>
</dependency>

commons-lang3提供的2个判断方法:

空字符串 一共分为3类:

null   这种就是 最真实的 为 空

""      这种不为空, 但是 长度为 0

" "     这种不为空,长度也不为0,但是 只包含 空格 字符

1.   isBlank 这种将 空字符串定义为: 

String s = null;

String s = "";

String s = "  ";

public static boolean isBlank(final CharSequence cs)

2.   isEmpty 这个方法 将空字符串定义为:

String s = null;

String s = "";

public static boolean isEmpty(final CharSequence cs) 

Finalizer

除了常见的 强软弱性引用外,还有一种引用:Finalizer引用

如果类重写了  finalize 方法,

 protected void finalize() throws Throwable { }

那么这个类在创建后,会被java.lang.ref.Finalizer  对象引用,该对象是一个链表结构

如何定义变量名称

      当我们在定义变量名称时,包括 : 数据库字段名称、Java编程语言 变量名称、 网络相关 比如 域名、接口名称、 等等 ,各种各样的场景下 需要定义 名称时, 都需要记住一点:定义的名称 不要有可能是 某种场景下的关键字

     在计算机体系中,使用高级语言编程,使用计算机,都是在整个体系中使用的,所以,有些名称是 在计算机体系中 已经存在的,我们不能拿来使用。就像是 程序的端口号一样,有些端口号是系统使用的,用户不能使用。

      因此,定义变量名时,需要有这方面的意识。

域名和IP是什么关系

一般来说,域名 经过 DNS 解析,会得到与之绑定的IP。

一个域名或者一个IP,可以绑定到不同的端口上,每个端口对应一个程序入口。

通常,在请求某个资源时,一般是用域名来请求,如果域名后面没有加端口号,那么会使用默认的端口号。但是,IP地址后面不能少了端口号。

因此,有可能会出现这种情况:

http://com.a.b/

http://com.a.b:8081/

http://com.a.b:8082/

http://com.a.b:8083/

或者

http://192.168.0.1:80

http://192.168.0.1:8081/

http://192.168.0.1:8082/

http://192.168.0.1:8083/

这些是 域名 或者 IP 相同,只是端口不同,那么就代表不同的资源地址。

域名和IP的绑定,可以通过  ping 命令来获取:

返回的IP地址,就是域名绑定的IP,也可以理解为 慢慢路由的起始端。 拿到这个IP,就可以访问的目标主机。

C:\Users>ping baidu.com

正在 Ping baidu.com [220.181.38.148] 具有 32 字节的数据:
来自 220.181.38.148 的回复: 字节=32 时间=29ms TTL=50
来自 220.181.38.148 的回复: 字节=32 时间=30ms TTL=50
来自 220.181.38.148 的回复: 字节=32 时间=32ms TTL=50
来自 220.181.38.148 的回复: 字节=32 时间=31ms TTL=50

因此,可以通过 ping 命令来获取具体的IP地址。

需要注意的是,ping命令 的域名后面,不要加端口号

如果,遇到访问某个网址 访问不通, 怎么解决呢?

 一般在开发的过程中,可以用一些 接口请求工具,比如postman,如果是get请求,也可以直接用浏览器 来请求我们的接口。

现在微服务盛行,在程序中发起的 对另一个服务的调用,都可以直接用 接口请求工具来访问。

当接口请求不通时,最好的方式,是用接口请求工具,把接口参数获取到后,直接请求,这样比较直观,可以根据当时的具体情况来判断问题所在。

可以从以下几点:

1. 资源的组成方面: 

域名解析是否成功

是http请求还是 https请求

端口是否正确

资源路径是否正确,一般资源路径:http(s)://域名:端口号/服务名/资源路径

请求方式GET/POST 是否正确

请求参数是否正确

必要的header、cookie等

        以上几点,仔细观察一下,了解清楚,保证信息都是正确的 就行。

2. 域名能否ping通这说明到目标主机的网络通不通。

        如果用IP可以访问通,用域名访问不通,说明 域名解析不成功

3. 能否请求到目标主机。

                现在比较流行k8s,容器,这样会涉及到不同范围的IP,可以理解成 局域网 套局域网,一层层嵌套,如果想要访问到内部的容器服务,需要从最外面的VIP 进行访问。

4. 目标主机是否存在请求资源。

        典型的是404,如果报了404,一定是网络是通的,主机能找到,只是主机上不存在你要请求的资源。

        资源不存在,返回404,这个时候 请求是成功的,只是返回了一个404告诉你资源不存在。所以,这里 在 编写网络通信相关的程序时,当发起了对资源的请求后,拿到结果,如果系统没有报错,不代表就是成功的,需要对返回码进行判断,只有200,才是成功。

5. 目标主机做了什么处理

      另一种情况是,在请求目标主机的过程中,被其他的中间服务,比如网关、F5等进行转发或者校验,也可能被拒绝 而导致访问不到目标主机。

      最终,如果请求到达目标主机,那么目标主机的一些策略,也可能导致我们的请求资源是拿不到的,比如:没有登录,被加到黑名单了等登。

因此,接口不通,原因很复杂,需要具体问题具体分析。

另外还有一点:在开发过程中,有开发环境、测试环境、灰度环境、生产环境等等各种环境,需要保证的是,环境是一致的。

判断一个类是不是另一个类的子类 

public native boolean isAssignableFrom(Class<?> cls)

Class 类提供的一个本地方法,可以快速判断一个类是不是另一个类的子类。

例如:Advice.class.isAssignableFrom(beanClass)

判断 beanClass 是不是 Advice 的子类

有了这个方法,就不用 获取Class的父接口,然后遍历 再判断了,非常方便。

编程注意事项:服务器硬件资源方面

这里讨论的是使用Java高级语言编写的程序。

程序运行最小单位是线程,线程运行需要一些资源:

1. CPU

2. memory

3. 磁盘IO/网络IO(带宽)

4. 线程生成的数据存放在磁盘上

        所以,再开发一个功能时,需要同时考虑上述 4 个大点,因为 一个程序不仅仅只有一个线程在运行,当新功能的线程 对上述 4 个大点 占用比较高,或者说 对服务器硬件资源 占用过高,会导致其他线程的正常执行,从而导致 某项功能无法正常提供。

        有一个原则是平均分配,也就是 所有不同的线程 对资源的使用都是平均的,这样大家才能 都正常的运行,正常的提供功能。

        另外一点,线程也有不同的类型、不同的执行优先级。比如:有守护线程,线程优先级有高有底。对于实际开发的功能,也存在 核心功能、辅助功能。但是 核心功能和辅助功能都是靠线程来执行的,所以,可以在编程的过程中,定制化的操作线程:比如 设置优先级、设置线程的个数、设置线程的运行频率等等。

        

泛型

变量和数据类型

boolean类型,hotspot 虚拟机 占4个字节,当成int来处理

在写代码的时候:

对于整数,是默认当成 int 类型的,如果超时 int 类型的范围,就会报错。

所以,在字面上面需要加上 L,标识一个 long型整数

浮点型默认的 double类型的

String.format 显示%

在Java中,如果你希望使用String.format方法输出百分号%,你需要使用两个连续的百分号%%来转义。这是因为%字符在格式化字符串中是特殊字符,用于引入格式化参数。当你想要文本中直接显示百分号时,写作%%会确保它被正确解析为一个单独的百分号字符。

String formattedText = String.format("显示百分比符号: %d%%", 100);
System.out.println(formattedText);

显示百分比符号: 100%

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值