Java基础001

1、Java中二维数组的length方法

1.1、
在一维数组a[ ]中,a.length 方法的意思就是返回这个数组的长度。
比如a[] = {1,2,3,4,5},则a.length = 5.
2.2、二位数组b[][]的length方法
在二位数组中,如果直接调用b.length方法,返回的则是b数组的行数,如果是b[0].length方法则返回的是0行所代表的长度。

public class arrTest {
 
	public static void main(String[] args) {
		int[][] b = new int[][]{{1,2},{1,2,3},{1,2,3,4},{1,2,3,4,5}};
		
		/*
		 * 1  2
		 * 1  2  3
		 * 1  2  3  4  
		 * 1  2  3  4  5 
		 */
		
		int length1 = b.length;
		int length2 = b[0].length;
		int length3 = b[1].length;
		int length4 = b[2].length;
		int length5 = b[3].length;
		
		System.out.println("length1=" + length1);
		System.out.println("length2=" + length2);
		System.out.println("length3=" + length3);
		System.out.println("length4=" + length4);
		System.out.println("length5=" + length5);
		
	}
}
 
 
result:
length1=4
length2=2
length3=3
length4=4
length5=5

2、设计模式

设计模式(Design pattern)是软件开发经验的总结,是软件设计中常见问题的典型解决方案。每个模式都像一个蓝图,您可以自定义以解决代码中的特定设计问题。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。
设计模式根据其意图或目的,分为三大类:
创建型模式【5个】
工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式【7个】
适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式【11个】
策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式和解释器模式。

在面试中,常见的设计模式包括工厂模式、代理模式、模板方法模式、责任链模式、单例模式、包装设计模式、策略模式等。其中,单例模式是Java中最常用的模式之一。
单例模式是一种创建型设计模式,它保证一个类只有一个实例,并提供一个访问它的全局访问点。在Java中,单例模式是最常用的设计模式之一。

类是一种抽象的数据类型,它是对一类对象的属性和行为的抽象描述。类是面向对象编程的基础,它定义了对象的属性和行为,并提供了一种封装数据和方法的机制。而对象则是类的一个实例,它具有类所描述的属性和行为。
类的定义语法如下:

[修饰符] class 类名 [extends 父类名] [implements 接口名] {
    // 类体
}

其中,修饰符可以是 public、protected、private 或者省略。类名是标识符,可以由字母、数字、下划线和美元符号组成,但不能以数字开头。extends 和 implements 是关键字,用于继承和实现接口。

对象是类的一个实例,有状态和行为。
类是一种抽象的概念,是对某一类事物的描述,而对象则是这类事物的具体实例。类是对象的模板,对象是类的实例。在Java中,一个类可以创建多个对象。下面是一个Java代码例子,展示了类与对象的关系:(在这个例子中,Dog是一个类,myDog是一个对象)

public class Dog {
   String breed;
   int age;
   String color;

   void barking() {
   }

   void hungry() {
   }

   void sleeping() {
   }
}

public class Main {
   public static void main(String[] args) {
      Dog myDog = new Dog();
      myDog.breed = "Labrador";
      myDog.age = 3;
      myDog.color = "black";
      myDog.barking();
   }
}

单例模式是一种创建型设计模式,它保证一个类只有一个实例,并提供一个全局访问点。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。在Java中,单例模式可以通过私有构造函数、静态变量和静态方法来实现。

下面是一个Java代码例子,展示了如何使用单例模式:(
在这个例子中,Singleton是一个单例类,getInstance()方法返回唯一的实例。)

public class Singleton {
//这行代码创建了一个名为instance的静态变量,
//它是Singleton类的唯一实例。
//它使用了Java中的静态初始化程序,这意味着它在类加载时被初始化,而不是在第一次使用时被初始化。
//这确保了Singleton实例在整个应用程序中只创建一次。
   private static Singleton instance = new Singleton();
//在Java中,new关键字用于创建一个新的对象。
//在这个例子中,new Singleton()创建了Singleton类的一个新实例,并将其分配给instance变量。这意味着instance变量现在引用Singleton类的唯一实例。
//在Java中,private是一种访问修饰符,用于限制类、方法和变量的访问。当一个类的成员被声明为private时,它只能在该类内部访问,而不能从其他类中访问³. 
//在C++中,static是一种关键字,用于指定类的成员变量或函数是静态的。静态成员变量是类的所有实例共享的,而不是每个实例都有自己的副本。静态成员函数是不与任何实例相关联的函数,它们只能访问静态成员变量和其他静态成员函数
   private Singleton() {}

   public static Singleton getInstance() {
      return instance;
   }

   public void showMessage() {
      System.out.println("Hello World!");
   }
}

public class Main {
   public static void main(String[] args) {
      Singleton object = Singleton.getInstance();
      object.showMessage();
   }
}

单例模式的实现方式

单例模式的5种实现方式

单例模式的优缺

单例模式是一种创建型设计模式,它保证一个类只有一个实例,并提供一个访问该实例的全局节点。

单例模式的优点是可以节省系统资源,减少内存开支,提高系统性能,还可以避免多个对象之间的冲突,从而提高代码的可维护性和可读性。特别是一个对象需要频繁地创建销毁时,而且创建或销毁时性能又无法优化,单例模式就非常明显了。由于单例模式只生成一个实例,所以,减少系统的性能开销。

因为单例模式在内存中只有一个实例,所以当一个对象需要频繁地创建销毁时,而且创建或销毁时性能又无法优化时,使用单例模式可以减少内存开支,提高性能。如果不使用单例模式,每次创建对象都会占用一定的内存空间,而且在销毁对象时也会释放一定的内存空间。如果对象的创建和销毁非常频繁,那么这些内存空间的分配和释放就会成为系统的瓶颈,从而影响系统的性能.

希望这可以回答您的问题。

单例模式的缺点是可能会导致代码复杂性增加,它可能会导致代码的耦合性增加,从而降低代码的灵活性和可扩展性。此外,如果单例类的实现不当,可能会导致线程安全问题。因此,在使用单例模式时需要谨慎考虑。

单例模式与静态类

单例模式和静态类有一些相似之处,但它们也有很大的区别。单例模式是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点。另一方面,静态类是一种类,其中所有成员都是静态的,因此不需要创建实例即可访问它们。

因此,单例模式和静态类之间的主要区别在于它们的目的。单例模式旨在确保一个类只有一个实例,并提供一个全局访问点。另一方面,静态类旨在提供一组相关的静态方法或属性,这些方法或属性可以在不创建实例的情况下访问

3、反射

Java反射是一种机制,它允许程序在运行时动态地获取类的信息并操作类的属性和方法。Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。Java反射机制主要包括以下三个部分:Class类、Constructor类和Method类。Class类表示一个类,Constructor类表示一个构造函数,Method类表示一个方法。Java反射机制可以用于很多场景,例如:动态代理、框架开发、注解处理器等等。
知乎详解

Java反射的优缺点

Java反射的优点是可以在运行时动态地获取类的信息并操作类的属性和方法,从而提高代码灵活度。Java反射机制的缺点是性能瓶颈,反射相当于一系列解释操作,通知 JVM 要做的事情,性能比直接的 Java 代码要慢很多。另外,Java反射机制也增加了类的安全隐患。反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。反射机制可以用于很多场景,例如:动态代理、框架开发、注解处理器等等。

Java反射 和 注解 和 动态代理 和 泛型 的区别

注解是一种标记,它可以用来标记类、方法、变量等。

反射则是一种机制,它可以在运行时动态地获取类的信息并操作类的属性和方法。

动态代理是一种设计模式,它可以在运行时动态地创建一个实现了一组给定接口的新类。

泛型是一种编译时机制,它可以在编译时检查类型是否一致,避免向下转型的强制类型转换的出错问题。

Java反射的实现

Java的反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态获取信息以及动态调用对象的方法的功能称为Java语言的反射机制。

Java反射机制主要包含以下三个部分:

  1. Class类:代表一个类的字节码文件,通过Class类可以获取一个类中的所有信息。
  2. java.lang.reflect包:提供了Field、Method、Constructor等类,分别用于描述类的属性、方法、构造器等信息。
  3. java.lang.ClassLoader类:负责将.class文件加载到内存中,并生成对应的Class对象。

Java反射机制实现主要有以下几个步骤:

  1. 获取Class对象:通过Class.forName()方法获取Class对象。
  2. 获取Constructor对象:通过Class对象获取Constructor对象。
  3. 创建实例:通过Constructor对象创建实例。
  4. 获取Method对象:通过Class对象获取Method对象。
  5. 调用方法:通过Method对象调用方法。

Java中反射的实现方式有如下几种:
1、通过Class.forName()方法加载字符串,就可以得到该字符串做代表的Class对象。例如:Class<?> clazz = Class.forName(\"java.lang.String\")就可以得到String类的Class对象。 2、通过类名.class获取,例如:Class<?> clazz = String.class;
3、通过对象.getClass()获取,例如:Class<?> clazz = “hello”.getClass();
4、通过ClassLoader.loadClass()方法获取,例如:ClassLoader.getSystemClassLoader().loadClass(“java.lang.String”)。

4、Java 语言是多线程的

在 Java 语言中,线程是一种特殊的对象,它必须由 Thread 类或其子(孙)类来创建。通常有两种方法来创建线程:其一,使用型构为 Thread(Runnable) 的构造子类将一个实现了 Runnable 接口的对象包装成一个线程,其二,从 Thread 类派生出子类并重写 run 方法,使用该子类创建的对象即为线程。值得注意的是 Thread 类已经实现了 Runnable 接口,因此,任何一个线程均有它的 run 方法,而 run 方法中包含了线程所要运行的代码。线程的活动由一组方法来控制。Java 语言支持多个线程的同时执行,并提供多线程之间的同步机制(关键字为 synchronized)。

Java 语言是多线程的,这意味着 Java 程序可以同时执行多个任务。Java 中的线程是轻量级的,因此在创建和使用线程时,开销很小。Java 中的多线程机制是通过 java.lang.Thread 类来实现的。Java 中有两种类型的线程:用户线程和守护线程。用户线程是指在程序中创建的线程,而守护线程是指在程序中没有明确创建的线程,它们通常用于执行后台任务,如垃圾回收和内存管理等。

Java 的多线程机制主要有三种实现方式:继承 Thread 类、实现 Runnable 接口和实现 Callable 接口。其中,继承 Thread 类是最简单的方法,但它也有一些缺点。例如,由于 Java 不支持多重继承,因此如果您的类已经继承了其他类,则无法使用此方法来创建新的线程。另外,如果您需要在多个类之间共享数据,则必须使用静态变量或其他方法来实现此目的。

进程:进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的一个独立单位。
举例:当你打开一个程序时,操作系统会为该程序创建一个进程。这个进程会包含该程序的代码和运行时所需的资源,例如内存、文件句柄等。当你关闭该程序时,操作系统会终止该进程并释放其占用的资源。

线程:线程是进程中的一个执行单元,负责当前进程中程序的执行。一个进程中至少有一个线程。线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。
举例:假设你正在使用一个文本编辑器,你可以同时进行多个操作,例如打字、拷贝、粘贴等。这些操作可以在不同的线程中执行,这样你就可以同时进行多个操作而不会感到卡顿。

进程是操作系统资源分配的基本单位,而线程是进程中的一个执行单元。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
每个进程都有自己的地址空间、数据栈以及其他系统资源,而线程共享进程的地址空间和系统资源。因此,线程之间的切换比进程之间的切换更快。
线程之间的分工可以通过线程的优先级、同步机制、互斥机制等方式来实现。线程的优先级决定了哪个线程会被先执行,同步机制可以保证多个线程之间的执行顺序互斥机制可以保证同一时间只有一个线程访问共享资源需要使用同步机制来保证线程安全。同步机制包括互斥锁、信号量、条件变量等。
两个不同的线程之间的区别在于它们执行的代码不同,或者说它们执行的任务不同
举例:一个线程可能负责读取数据,另一个线程可能负责处理数据。这些线程之间可以通过同步和互斥机制来协调它们的工作。

协程:。在Java中,协程被称为轻量级进程。协程是一种用户态的轻量级线程,它不需要操作系统的支持,可以在用户态中完成调度。协程的调度是由程序员自己控制的,因此可以避免操作系统在进程和线程之间切换时的开销。协程可以看作是一种更轻量级的线程,它不需要操作系统的支持,可以在用户态中完成调度。
协程和线程的区别主要有以下几点:

  1. 调度方式不同:线程的调度是由操作系统完成的,而协程的调度是由程序员自己控制的。
  2. 调度开销不同:线程的调度需要切换到内核态,开销较大,而协程的调度是在用户态中完成的,开销较小。
    内核态和用户态是指CPU的运行级别。在内核态下,CPU可以访问所有的硬件资源,而在用户态下,CPU只能访问受限的硬件资源。操作系统内核运行在内核态,应用程序运行在用户态。当应用程序需要访问操作系统提供的服务时,需要通过系统调用从用户态切换到内核态。
  3. 并发性不同:线程是并发执行的,而协程是顺序执行的,但可以通过多个协程之间的切换来实现并发。
  4. 内存占用不同:线程需要独立的栈空间,而协程可以共享栈空间。

多进程与duo线程

多线程和多进程都是并发编程的方式,但是它们的实现方式不同。多进程是指在操作系统中能同时运行多个程序,每个程序运行的时候都有一个独立的进程,而多线程是指在同一程序中有多个不同的执行路径。

具体来说,一个应用程序至少包括1个进程,而1个进程包括1个或多个线程,线程的尺度更小。每个进程在执行过程中拥有独立的内存单元,而一个线程的多个线程在执行过程中共享内存。

因此,多进程和多线程之间的主要区别在于它们如何使用内存。在多进程中,每个进程都有自己独立的内存空间,而在多线程中,所有线程共享相同的内存空间。这意味着,在多线程中,所有线程都可以访问相同的变量和数据结构,而在多进程中,每个进程都有自己独立的变量和数据结构。

此外,在多进程中,由于每个进程都有自己独立的内存空间,因此它们之间不会相互干扰。但是,在多线程中,由于所有线程共享相同的内存空间,因此它们之间可能会相互干扰。这就需要使用锁等机制来确保数据安全性。

序列化与反序列化

参考链接
java序列化指的是将java对象转化为字节序列的过程。
java反序列化指字节序列恢复到java对象。

一个字节(byte)有八个比特位,即 byte = 8*bit。
如果八个bit位都为1,即这个字节最大为 FF = 1111 1111。
一个字(word)是两个byte,即 word = 2 byte = 16 bit,比如0x12345678就需要四个字节
tcp/ip协议出来之后就规定网络通信必须使用大端序。
大端序从头开始。
12 34 56 78

序列化:

对象序列化的最主要的用处就是在传递和保存对象的时候,保证对象的完整性和可传递性。序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。序列化后的字节流保存了Java对象的状态以及相关的描述信息。序列化机制的核心作用就是对象状态的保存与重建。

反序列化:

客户端从文件中或网络上获得序列化后的对象字节流后,根据字节流中所保存的对象状态及描述信息,通过反序列化重建对象。

序列化就是把实体对象状态按照一定的格式写入到有序字节流,反序列化就是从有序字节流重建对象,恢复对象状态。上面的简单点说,进程间通信可以将图片,视频,音频等信息用二进制方式传输。但是进程间的对象却不能这么搞。

多线程下使用HashMap

参考链接
参考链接
HashMap内部使用一个数组链表的方式来实现,ashMap使用了一个Entry数组,而Entry类又包含一个类型为Entry的next变量,也就相当于是一个链表,所有根据 hash 值计算的 bucket 一样的 key 会存储到同一个链表里(即产生了冲突)。
HashMap 内部的 Entry 数组默认的大小是16,假设有100万个元素,那么最好的情况下每个 hash 桶里都有62500个元素,这时get(),put(),remove()等方法效率都会降低。为了解决这个问题,HashMap 提供了自动扩容机制,当元素个数达到数组大小loadFactor 后会扩大数组的大小,在默认情况下,数组大小为16,loadFactor 为0.75,也就是说当 HashMap 中的元素超过16\0.75=12时,会把数组大小扩展为216=32,并且重新计算每个元素在新数组中的位置。
简单来说:假设两个线程同时进行put操作,并且两个put操作元素的key发生了碰撞(根据 hash 值计算的 bucket 一样),那么根据 hashMap 的实现,这两个值将会添加到数组的同一个地方,那么就会有一个值被覆盖,因为造成了数据丢失,所以 HashMap 线程不安全

HashMap 中更为危险的是,HashMap 在并发执行扩容操作时会引起死循环,导致 CPU 利用率接近100%。因为多线程会导致 HashMap 的 Entry 链表形成环形数据结构,一旦形成环形数据结构,Entry 的 next 节点永远不为空,就会在获取 Entry 时产生死循环。形成环形链表的原因主要跟 JDK1.7 下 HashMap 发生碰撞后,链表是前序插入有关
图片解释

如何线程安全的使用 HashMap。这个无非就是以下三种方式:

1.Hashtable(Hashtable 是将绝大部分方法都加上 synchronized 来保证线程安全的,由于绝大部分方法都同步,所以它的性能低下,是jdk1.0遗弃的类,不建议使用
2.Sysnchronized Map(Sysnchronized Map 和 Hashtable 相似,也是采用 synchronized 来保证线程安全的,唯一不同的是,SysnchronizedMap使用一个 Object 对象进行同步,并且它也没有被没遗弃
3.ConcurrentHashMap(ConcurrentHashMap 是 java.util.concurrent 包下的一个类,该包下拥有许多线程安全、测试良好、高性能的类,大家有兴趣可以去看看。同 Hashtable 相比,ConcurrentHashMap 不仅保证了访问的线程安全性,而且在效率上有较大的提高。相对 HashMap 和 Hashtable, ConcurrentHashMap 增加了Segment 层,每个 Segment 原理上等同于一个 Hashtable。向 ConcurrentHashMap 中插入数据或者读取数据,首先都要讲相应的 Key 映射到对应的 Segment,因此不用锁定整个类, 只要对单个的 Segment 操作进行上锁操作就可以了。理论上如果有 n 个 Segment,那么最多可以同时支持 n 个线程的并发访问,从而大大提高了并发访问的效率。另外 rehash() 操作也是对单个的 Segment 进行的,所以由 Map 中的数据量增加导致的 rehash 的成本也是比较低的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值