第三次练习

前端作业js基础

js中var和let的差异

  作用域差异:var声明的变量具有函数作用域或全局作用域;let声明的变量具有块作用域,只能在包含它的代码块内部访问。
  变量提升行为:var声明的变量会发生变量提升,在代码执行之前,变量的声明会被提升到作用域的顶部,但赋值不会提升;let声明的变量不会提升,在声明前访问会抛出错误。
  重复声明:同一作用域中,var允许重复声明同一个变量,而let不允许。

js中的函数定义方式

  1/ 函数声明:function函数名(参数){//函数体}
  2/ 函数表达式:let 变量名=function(参数){//函数体}
  3/ 箭头函数:let 变量名=(参数)=>{//函数体}
  4/ 函数构造器:let 函数名=new function('参数1','参数2','函数体');
  5/ 方法简写:let 对象={方法名(参数){//函数体}}

匿名函数与普通函数的区别

  1>命名:普通函数有名称,匿名函数没有
  2>引用:普通函数可通过名称直接调用,匿名函数需赋值给变量或作为参数传递
  3>用途:匿名函数常用于回调、IIFE及事件处理
  4>堆栈跟踪:普通函数在错误堆栈中显示函数名,匿名函数更难调试

 箭头函数

  1>语法简洁:单参数可省略括号,单语句可省略return和{}
  2>无this绑定:继承上下文this,没有自己的this
  3>不能当构造函数:不能用new调用
  4>没有arguments对象:使用剩余参数(..args)代替
  5>无prototype属性:不能用于继承
  6>不能使用yield:不能作为生成器函数

js中的变量类型

 1/基本数据类型:number、string、Boolean、null、undefined、symbol、bigint
  2/引用数据类型:object、array、function、date、regexp等

 拓展

  变量赋值:发生在基本数据类型赋值时
  引用赋值:发生在引用类型赋值时
  函数在js中特殊的对象,属于引用类型,可以赋值给变量,可以作为参数传递,可以作为返回值。可以像其他变量一样使用,但赋值时遵循引用赋值的规则

 for、foreach、for in、for of

  for:最基础的循环方式;可以精确控制循环的起始和步长;可以使用break/continue;适用于需要使用索引的场景

for(let i=0;i<10;i++){}


  foreach: 更现代的函数式写法;不能使用break/continue;不能提前终止循环;适用于需要遍历数组每个元素的场景

const array=[1,2,3];
array.foreach((item,index,array)=>{})  


  for in: 主要用于遍历对象的可枚举属性;会遍历原型链上的属性;不适合遍历数组(因为会遍历数组的其他属性);可以使用break/continue

const obj={a:1,b:2,c:3};
for(let key in obj){}  


  for of:  ES6新增的遍历方式;可以遍历所有可迭代对象(Array, Map, Set, String等);直接获取值而不是索引;可以使用break/continue;不能遍历普通对象 

const array=[1,2,3];
for(let value of array){}

拓展

  迭代器和生成器:迭代器时一个对象,定义了一个序列,终止时可能返回一个返回值
  生成器时一种特殊的函数,可以通过yield关键字暂停和恢复执行

json转换为字符串

// 使用Jackson库
ObjectMapper mapper = new ObjectMapper();
String jsonString = mapper.writeValueAsString(object);
// 使用Gson库
Gson gson = new Gson();
String jsonString = gson.toJson(object);
  字符串转对象
// 使用Jackson库
ObjectMapper mapper = new ObjectMapper();
MyClass obj = mapper.readValue(jsonString, MyClass.class);
// 使用Gson库
Gson gson = new Gson();
MyClass obj = gson.fromJson(jsonString, MyClass.class);

 object、{}和Map的区别

Object(Java)

是所有Java类的根类
包含基础方法如equals()、hashCode()等
可以存储任何类型的对象

{}(JavaScript)

是JavaScript中的对象字面量表示法
是一个动态的键值对集合
可以随时添加或删除属性
属性可以是任何类型

Map(Java) 

是一个接口,定义了键值对的集合
有多种实现如HashMap、TreeMap等
提供了特定的方法操作键值对
可以指定键和值的类型   

JavaScript对象属性顺序

JavaScript对象的属性顺序遵循以下规则 

数字键:
首先按照数值大小升序排列
字符串键:
按照属性被添加的顺序排列
ES2015+规范保证了这个顺序 

属性顺序会在以下情况发生改变 

 删除属性后重新添加
对象被序列化后再解析
使用Object.assign()等方法合并对象
通过不同方式(如Proxy)访问对象

 后端作业 java语法基础

java变量的基本类型 

  整数类型:byte,short,int,long
  浮点类型:float,double
  字符类型:char
  布尔类型:boolean 

封装类型和基本类型的关系 

  byte -> Byte
  short -> Short
  int -> Integer
  long -> Long
  float -> Float
  double -> Double
  char -> Character
  boolean -> Boolean 

进阶 

基本数字类型转换 

 向下转换(大类型转小类型):

  • 可能会发生数据截断
  • 遵循补码规则
  • 截取低位字节
  • 可能导致精度损失

 向上转换(小类型转大类型):

  • 自动进行,无需显式转换
  • 不会发生数据丢失
  • 高位补符号位

封装类型转换 

 当基本类型和包装类型互相转换时

  • 自动装箱实际调用Integer.valueOf()
  • 自动拆箱实际调用intValue()

对象创建方式的区别 

 Integer的创建:

区别:

  • new Integer()始终创建新对象
  • 自动装箱会使用缓存池(-128到127之间的值)

String的创建:

区别:

  • new String()会在堆内存创建新对象
  • 直接赋值会先检查字符串常量池,有则复用,无则创建

缓存池使用规则 

 Integer缓存池:
  • 范围:-128到127
  • 通过Integer.valueOf()方法获取
  • 超出范围会创建新对象
String常量池:
  • 字符串字面量直接使用常量池
  • intern()方法可以将堆上的字符串对象添加到常量池

 Java对象实例的生成方式

 使用new关键字(最常用)

Student student = new Student();

 使用Class类的newInstance()方法

Student student = Student.class.newInstance();

使用Constructor类的newInstance()方法

Constructor<Student> constructor = Student.class.getConstructor();
Student student = constructor.newInstance();

使用Clone方法

Student student2 = (Student) student1.clone();

使用反序列化

ObjectInputStream in = new ObjectInputStream(new FileInputStream("student.obj"));
Student student = (Student)in.readObject();

对象的回收 

   Java对象的回收由垃圾收集器(Garbage Collector,GC)自动完成。当对象变成不可达(unreachable)时,就可能被回收。对象变成不可达的情况包括:

  • 对象没有被任何引用指向
  • 对象的引用超出了作用域
  • 引用被显式设置为null

 四种引用类型

1) 强引用(Strong Reference)

Object obj = new Object(); 

特点:

  • 最常见的引用类型
  • 只要强引用存在,垃圾收集器永远不会回收被引用的对象
  • 即使内存不足,JVM也不会回收,而是抛出OutOfMemoryError

2) 软引用(Soft Reference)

SoftReference<Object> softRef = new SoftReference<Object>(new Object());

特点:

  • 内存充足时不会被回收
  • 内存不足时会被回收
  • 常用于实现内存敏感的高速缓存

3) 弱引用(Weak Reference)

WeakReference<Object> weakRef = new WeakReference<Object>(new Object());

特点:

  • 下一次垃圾收集发生时,无论内存是否充足,都会被回收
  • 常用于避免内存泄漏,如WeakHashMap

4) 虚引用(Phantom Reference)

ReferenceQueue<Object> queue = new ReferenceQueue<>();
PhantomReference<Object> phantomRef = new PhantomReference<Object>(new Object(), queue);

特点:

  • 最弱的引用关系
  • 随时可能被回收
  • 必须和ReferenceQueue一起使用
  • 主要用于跟踪对象被垃圾回收的状态

 Java中的遍历方式

 for循环(普通for循环)

for (int i = 0; i < array.length; i++) {
    System.out.println(array[i]);
}

特点:

  • 最基础的循环方式
  • 可以控制循环的起始位置和步长
  • 可以同时遍历多个数组
  • 适合需要使用索引的场景

增强for循环(for-each) 

for (String item : list) {
    System.out.println(item);
}

 特点:

  • 语法简洁,代码可读性强
  • 不能获取索引位置
  • 不能修改集合中的元素
  • 适合只读遍历场景

 while循环

int i = 0;
while (i < list.size()) {
    System.out.println(list.get(i));
    i++;
}

特点:

  • 适合不知道具体循环次数的场景
  • 可以灵活控制循环条件
  • 需要手动控制索引递增

Iterator迭代器

Iterator<String> it = list.iterator();
while (it.hasNext()) {
    String item = it.next();
    System.out.println(item);
}

特点:

  • 可以在遍历过程中安全地删除元素
  • 只能单向遍历
  • 提供了统一的遍历接口

 迭代器(Iterator) 

迭代器是一种设计模式,提供了一种方法来访问集合中的元素,而不需要暴露其底层的表示方式。

主要方法:

  • hasNext(): 判断集合中是否还有元素
  • next(): 获取下一个元素
  • remove(): 删除当前元素
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    public class IteratorExample {
        public static void main(String[] args) {
            // 创建ArrayList集合
            List<String> fruits = new ArrayList<>();
            fruits.add("苹果");
            fruits.add("香蕉");
            fruits.add("橙子");
            
            // 使用Iterator遍历并删除特定元素
            Iterator<String> iterator = fruits.iterator();
            while (iterator.hasNext()) {
                String fruit = iterator.next();
                if (fruit.equals("香蕉")) {
                    iterator.remove(); // 安全地删除元素
                } else {
                    System.out.println(fruit);
                }
            }
        }
    }

 static,const,final

static(静态) 

  • 表示某个成员属于类本身,而不是类的实例
  • 可以不创建对象实例就能访问
  • 被所有实例共享
 可以使用的位置
 类成员变量
class Example {
    static count = 0;
}
 类方法
class Example {
    static sayHello() {
        console.log('Hello');
    }
}
类块内部
class Example {
    static {
        // 静态初始化块
    }
}

const(常量) 

  • 声明一个不可重新赋值的变量
  • 值不可变(对于基本类型),但对象的属性可以修改
  • 必须在声明时初始化 
 可以使用的位置
 变量声明
const PI = 3.14159;
 函数参数
function process(const param) {}
 类中的只读属性(某些语言支持)
class Example {
    readonly constant = 42; // TypeScript中的写法
}

final(最终)

  • 在Java等语言中使用,JavaScript没有此关键字
  • 表示某个实体不能被修改或继承
  • 类似于const和readonly的组合
 可以使用的位置
 类声明
final class Example {
    // 此类不能被继承
}
 方法声明
class Example {
    final void method() {
        // 此方法不能被重写
    }
}
变量声明
final int constant = 100;

 if else,switch case,三目运算符

if-else 语句 

  • 按顺序执行条件判断,直到找到第一个为真的条件
  • 每个条件都是独立判断,不存在跳转表
  • 当条件较多时,时间复杂度为 O(n)
  • 编译器可能会对简单的 if-else 进行优化

 switch-case 语句

  • 编译器通常会将 switch-case 优化成跳转表(jump table)或查找表
  • 跳转表使得执行时间与 case 数量无关,时间复杂度为 O(1)
  • 但需要额外的内存来存储跳转表
  • 只适用于整型值(包括枚举)的比较
  • 当 case 值不连续或差距较大时,可能会退化成 if-else 结构

 三目运算符(?:)

  • 通常编译成单个条件跳转指令
  • 只能处理二元条件(真/假)
  • 由于结构简单,编译器容易优化
  • 在字节码层面通常比 if-else 更紧凑

 equals()是用什么进行比较的,两字符串为什么用 == 无法比较。

  equals() 方法比较原理

  • equals() 默认实现(来自Object类)是使用 == 进行比较,比较的是对象的引用(内存地址)
  • 很多类(如String、Integer等)都重写了equals()方法,用于比较对象的内容而不是引用
  • 例如String类的equals()重写后会逐个比较字符串中的字符 

  为什么字符串不能用 == 比较

  • == 运算符比较的是对象的引用(内存地址),而不是字符串的内容
  • 当使用字符串字面量时,Java会将其存入字符串常量池
  • 使用new创建的字符串会在堆内存中创建新对象
  • 所以即使两个字符串内容相同,它们的引用可能不同

hashcode() 

hashCode()的默认返回值

默认的hashCode()方法返回的是对象在JVM中的内存地址转换成的一个整数。这个值是由JVM根据对象的内存地址计算得出的,但具体的计算方式可能因不同的JVM实现而异。

 重写hashCode()会影响的函数

  • HashMap的put/get/remove等操作
  • HashSet的add/remove/contains等操作
  • Hashtable的相关操作
  • 任何依赖hashCode()的缓存实现

 HashMap和HashSet

 HashMap的判断机制

   首先使用hashCode()计算对象的哈希值

   根据哈希值确定对象在内部数组中的存储位置

   如果该位置已经有元素:

  • 先比较hashCode值是否相等
  • 如果hashCode相等,再调用equals()方法进行比较
  • 只有当hashCode相等且equals()返回true时,才认为是同一个对象

 HashSet的判断机制

   HashSet内部实际上是使用HashMap来实现的

   当我们使用HashSet时,实际上是将元素作为HashMap的key来存储

   判断重复的逻辑与HashMap完全相同:

  • 先比较hashCode()
  • 如果hashCode相等,再比较equals()
  • 两者都相等才认为对象是重复的

 Java序列化和反序列化基础

  • 序列化(Serialization):将Java对象转换为字节序列的过程
  • 反序列化(Deserialization):将字节序列恢复为Java对象的过程

实现接口 

  • Java使用Serializable接口来实现序列化
  • 这是一个标记接口(marker interface),不需要实现任何方法

 Fastjson序列化与反序列化Map

 Map转JSON字符串

// Map转JSON
Map<String, Object> map = new HashMap<>();
map.put("name", "张三");
map.put("age", 25);

// 序列化
String jsonString = JSON.toJSONString(map);

 JSON字符串转Map

// JSON转Map
String jsonString = "{\"name\":\"张三\",\"age\":25}";

// 反序列化
Map<String, Object> map = JSON.parseObject(jsonString, Map.class);

Fastjson的工作原理

   序列化过程
  • 使用反射获取对象的属性信息

  • 遍历Map的键值对

  • 将每个键值对转换为JSON的key-value形式

  • 处理特殊类型(如日期、数字等)

   反序列化过程
  • 解析JSON字符串为词法单元

  • 根据目标类型(Map)创建对象
  • 解析键值对并填充到Map中
  • 自动类型转换(如String到Integer等)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值