MyMap

package com.zhuyu_deng.test;

import com.zhuyu_deng.test.MyTreeMap.Entry;

public class MyMap<K, V>
{
//	属性
//	root:TreeMap,需要有树根
	private Entry<K, V> root;
//	currentSize:当前树中结点数
	private int currentSize;
//	modCount:修改次数;不可并发;
	private int modCount;
	
//	定义常量
	private static final boolean BLACK = true;
	private static final boolean RED = false;
	
	static class Entry<K, V>
	{
//																属性
		K key;
		V value;
		Entry<K, V> left = null;
		Entry<K, V> right = null;
		Entry<K, V> parent;
		boolean color = BLACK;
		
//																方法
//		新生成的结点都是叶子结点,所有left,right都为NULL;
		Entry(K key, V value, Entry<K, V> p)
		{
			this.key = key;
			this.value = value;
			parent = p;
		}
		public K getKey()
		{
			return key;
		}
		public V getValue()
		{
			return value;
		}
		
		public V setValue(V newValue)
		{
			V oldValue = value;
			value = newValue;
			return oldValue;
		}
		
		public int hashCode()
		{
			return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode());
		}
		
		public boolean equals(Object o)
		{
			if (!(o instanceof Entry))
				return false;
			Entry<K, V> e =(Entry<K, V>) o;
			
			return valEquals(key, e.getKey()) && valEquals(value, e.getValue());  // 对数据的访问尽量用方法,不要直接调用数据(尤其是内部数据)
		}
		
		private boolean valEquals(Object o1, Object o2)
		{
			return (o1 == null ? o2 == null : o1.equals(o2));  // 挺好的这段代码,值得学习。
		}
		
		public String toString()
		{
			return key + " = " + value;
		}
	}
//  方法
	public MyMap()
	{
		
	}
	
	public int size()
	{
		return currentSize;
	}
	
	public V get(Object key)
	{
		Entry<K, V> x = getEntry(key);
		return x == null ? null : x.value;
	}
//	如果是覆盖,这返回原来的value,否则返回null。
	public V put(K key, V value)
	{
		Entry<K, V> t = root;
		if (t == null)
		{
			root = new Entry<K, V>(key, value, null);  // debug了半个小时。
			currentSize++;
			modCount++;
			return null;
		}
		
		Entry<K, V> parent;
//	找到需要put的位置
		if (key == null)
			throw new NullPointerException();
		Comparable<? super K> k = (Comparable<? super K>) key;
		int cmp = 0;
		do
		{
			parent = t;
			cmp = k.compareTo(parent.key);
			if (cmp < 0)
				t = parent.left;
			else if (cmp > 0)
				t = parent.right;
			else
			{
				return t.setValue(value);
			}
		}while (t != null);
//		t指向了null
		Entry<K, V> e = new Entry<K, V>(key, value, parent);
		if (cmp < 0)
			parent.left = e;
		else
			parent.right = e;
		fixupAfterInsertion(e);
		currentSize++;
		modCount++;
		return null;
	}
	
//	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	public V remove(Object key)
	{
		Entry<K, V> x = getEntry(key);
		if (x == null)
			return null;
		V oldValue = x.value;
		deleteEntry(x);
		return oldValue;
	}
//	///////////////////////////////////////////////////////////////////////////////////////////////////
	private Entry<K, V> getEntry(Object key)
	{
		if (key == null)
			throw new NullPointerException();
		Comparable<? super K> k = (Comparable<? super K>) key;
		Entry<K, V> p = root;
		while (p != null)
		{
			int cmp = k.compareTo(p.key);
			if (cmp < 0)
				p = p.left;
			else if (cmp > 0)
				p = p.right;
			else
				return p;
		}
		return null;
	}
//	Insert后只可能破坏:
//	
//	1)根节点是黑色的
//	2)红结点有两个黑孩子, x and p[x] 同时为红色,所以while循环的目的就是解决:双红问题,这存在3中情况; 由父亲的兄弟颜色决定,1)红色的兄弟;2)黑色兄弟(黑色兄弟分为两种情况),x在右;3)黑色兄弟,x在左;

//	插入的结点一定是一个叶子结点;可能破坏property:1)根是黑的,2)双红,分别由root.color == BLACK和while循环保持性质。
	private void fixupAfterInsertion(Entry<K, V> x)
	{
//		默认插入的结点为红色
		x.color = RED;
//		                    x是根的时候直接赋值;    x不是根,且父亲的颜色为红色的时候才被循环。
		while (x != null && x != root && x.parent.color == RED)  // 双红
		{
//			主要和x的父亲是x的爷爷的左侧还是右侧决定的,主要和x的叔父的颜色有关系(在处理双红问题时)
			if (parentOf(x) == leftOf(parentOf(parentOf(x))))  // p[x]为p[p[z]]的左孩子
			{
				Entry<K, V> y = rightOf(parentOf(parentOf(x)));
				if (colorOf(y) == RED)
				{
					setColor(y, BLACK);
					setColor(parentOf(x), BLACK);
					setColor(parentOf(parentOf(x)), RED);
					x = parentOf(parentOf(x));
				}
				else
				{
					if (x == rightOf(parentOf(x)))
					{
						x = parentOf(x);
						rotateLeft(x);
					}
					else
					{
						setColor(parentOf(x), BLACK);
						setColor(parentOf(parentOf(x)), RED);
						rotateRight(parentOf(parentOf(x)));
					}
				}
			}
			else
			{
				Entry<K, V> y = leftOf(parentOf(parentOf(x)));
				if (colorOf(y) == RED)
				{
					setColor(y, BLACK);
					setColor(parentOf(x), BLACK);
					setColor(parentOf(parentOf(x)), RED);
					x = parentOf(parentOf(x));
				}
				else
				{
					if (x == leftOf(x))
					{
						x = parentOf(x);
						rotateRight(x);
					}
					else
					{
						setColor(parentOf(x), BLACK);
						setColor(parentOf(parentOf(x)), RED);
						rotateLeft(parentOf(parentOf(x)));
					}
				}
			}
		}
		root.color = BLACK;
	}
//	走到了这一步说明确定要删除一个结点,并且被删除的结点确实存在。
	private void deleteEntry(Entry<K, V> x)
	{
		modCount++;
		currentSize--;
//		case 1: two children.
		if (x.left != null && x.right != null)
		{
			Entry<K, V> s = successor(x);  // leaf or have a child.
			x.key = s.key;
			x.value = s.value;
			x = s;  // x always point to the node which will be deleted.
		}
//		after if implement, x point to the node having no child or one child.
		Entry<K, V> replacement = (x.left != null ? x.left : x.right);
		
		if (replacement != null)
		{
			replacement.parent = x.parent;
			
			if (x.parent == null)
				root = replacement;
			else if (x == x.parent.left)
				x.parent.left = replacement;
			else
				x.parent.right = replacement;
			
			x.left = x.right = x.parent = null;
			
			if (x.color == BLACK)
				fixAfterDeletion(replacement);
			
		}
		else if (x.parent == null)  // have no children. there is only one node.
		{
			root = null;
		}
		else
		{
			if (x.color == BLACK)
				fixAfterDeletion(x);
			
			if (x.parent != null)
			{
				if (x == x.parent.left)
					x.parent.left = null;
				else 
					x.parent.right = null;
			}
		}
	}
//	Utilities
	private Entry<K, V> parentOf(Entry<K, V> x)
	{
		return x == null ? null : x.parent;
	}
	private Entry<K, V> leftOf(Entry<K, V> x)
	{
		return x == null ? null : x.left;
	}
	private Entry<K, V> rightOf(Entry<K, V> x)
	{
		return x == null ? null : x.right;
	}
	private boolean colorOf(Entry<K, V> x)
	{
		return x == null ? BLACK : x.color;
	}
	private void setColor(Entry<K, V> x, boolean c)
	{
		if (x != null)
			x.color = c;
	}
	
	private void rotateLeft(Entry<K, V> x)
	{
		if (x != null)
		{
			Entry<K, V> r = rightOf(x);
			x.right = r.left;
			if (r.left != null)
				r.left.parent = x;
			
			r.parent = x.parent;
			if (x.parent == null)
				root = r;
			else
			{
				if (x == leftOf(x))
					x.parent.left = r;
				else
					x.parent.right = r;
			}
			
			x.parent = r;
			r.left = x;
		}
	}
	
	private void rotateRight(Entry<K, V> x)
	{
		if (x != null)
		{
			Entry<K, V> lt = x.left;
			
			x.left = lt.right;
			if (lt.right != null)
				lt.right.parent = x;
			
			lt.parent = x.parent;
			if (x.parent == null)
				root = x;
			else
			{
				if (x == parentOf(x))
					x.parent.left = lt;
				else
					x.parent.right = lt;
			}
			
			x.parent = lt;
			lt.right = x;
		}
	}
	
	private Entry<K, V> successor(Entry<K, V> x)
	{
//		case 1
		if (x == null)
			return null;
//		case 2
		else if (x.right != null)
		{
			Entry<K, V> t = x.right;
			while (t.left != null)
			{
				t = t.left;
			}
			return t;
		}
//		case 3
//		                   d
//		                c
//		                  b
//		                    a <- x
//		
		else
		{
			Entry<K, V> p = x.parent;
			Entry<K, V> ch = x;
			while (p != null && ch == p.right)
			{
				ch = p;
				p = p.parent;
			}
			return p;
		}
	}

//	x 指向被赋予了一层黑色的结点。
	private void fixAfterDeletion(Entry<K, V> x)
	{
//		x 是指向被赋予了一层黑色的结点,while循环(当x双重黑色的时候)
		while (x != root && colorOf(x) == BLACK)  // when x is root, make it BLACK directly.
		{
			if (x == leftOf(parentOf(x)))
			{
				Entry<K, V> sib = rightOf(parentOf(x));
				if (colorOf(sib) == RED)
				{
					setColor(parentOf(x), RED);
					setColor(sib, BLACK);
					rotateLeft(parentOf(x));
					sib = rightOf(parentOf(x));  // 记住每次都要重新置兄弟值。
				}
				else if (colorOf(leftOf(sib)) == BLACK && colorOf(rightOf(x)) == BLACK)
				{
					setColor(sib, RED);
					x = parentOf(x);
				}else
				{
//					要这样写代码,因为case3之后,可能进入case4;
					if (colorOf(rightOf(sib)) == BLACK)
					{
						setColor(sib, RED);
						setColor(leftOf(sib), BLACK);
						rotateRight(sib);
						sib = rightOf(parentOf(x));
					}
					
					setColor(sib, colorOf(parentOf(x)));
						setColor(parentOf(x), BLACK);
						setColor(rightOf(sib), BLACK);
						rotateLeft(parentOf(x));
						x = root;
				}
			}
			else
			{
				Entry<K, V> sib = leftOf(parentOf(x));  // 删除后的4种情况,由x的兄弟决定的。
				
				if (colorOf(sib) == RED)
				{
					setColor(parentOf(x), RED);
					setColor(sib, BLACK);
					rotateRight(parentOf(x));
					sib = leftOf(parentOf(x));
				}
				else if (colorOf(leftOf(sib)) == BLACK && colorOf(rightOf(sib)) == BLACK)
				{
					setColor(sib, RED);
					x = parentOf(x);
				}
				else
				{
					if (colorOf(leftOf(sib)) == BLACK)
					{
						setColor(sib, RED);
						setColor(rightOf(sib), BLACK);
						rotateLeft(sib);
						sib = leftOf(parentOf(x));
					}
					setColor(sib, colorOf(parentOf(x)));
					setColor(parentOf(x), BLACK);
					rotateRight(parentOf(x));
					x = root;
					
				}
			}	
		}
//		x 原来是红色的,直接红色就可以了。
		setColor(x, BLACK);
	}
}

<think>我们正在处理的是JMeterBeanShell环境中的Map初始化问题。用户之前遇到了使用逗号初始化Map的语法错误,现在又提到了关于`myMap.put`的未知语法错误。结合之前的上下文,我们需要确保在BeanShell中正确使用HashMap。在BeanShell中,初始化HashMap的正确方式是:1.导入必要的Java类(如HashMap)。2.使用`newHashMap<>()`创建实例(注意BeanShell可能不完全支持泛型,但可以声明)。3.使用`put`方法逐个添加键值对。根据用户上一次的问题,我们已经给出了正确的示例。现在用户再次提到编译或语法错误,可能是由于以下原因:-没有正确导入包(如`java.util.HashMap`)。-在声明Map时使用了不支持的语法(如使用泛型虽然BeanShell可能允许,但有时会有问题)。-键或值没有使用双引号(字符串必须用双引号括起来)。-在BeanShell中,如果语句结束没有使用分号,可能会导致错误(虽然BeanShell允许省略分号,但建议加上)。因此,我们给出一个更加强调避免错误的示例,并解释关键点。</think> ### 🛠️ Java Map 初始化与 `put()` 方法语法错误的解决方案 #### 🔍 问题原因分析 在 `Map<String,String> map = new HashMap<>(); myMap.put...` 代码中,常见错误有: 1. **泛型未正确声明** `new HashMap<>()` 的尖括号缺失类型声明时可能导致 IDE 混淆 ✅ 解决方案:补全泛型声明 `new HashMap<String, String>()` 2. **变量名不一致** `map` 声明后却使用 `myMap.put` 导致 "unknown error" ✅ 确保变量名统一:`map.put()` 而非 `myMap.put()` 3. **JMeter BeanShell 特殊限制** BeanShell 不完全支持 Java 8+ 特性[^1] ✅ 避免语法糖,使用显式类型声明 #### ✅ 完整修复代码 ```java // 必须显式导入包 import java.util.HashMap; import java.util.Map; // 修复1:完整泛型声明 + 统一变量名 Map<String, String> map = new HashMap<String, String>(); // 修复2:正确调用put方法(参数用双引号包裹) map.put("key1", "value1"); // ✅ 字符串键值必须加双引号 map.put("key2", "value2"); // 调试输出 log.info("Map内容:" + map.toString()); // JMeter专属日志方法 ``` #### ⚠️ 关键注意事项 1. **JMeter 环境限制** ```java // ❌ BeanShell 不支持类型推断 Map<String, String> map = new HashMap<>(); // ✅ 必须显式声明泛型 Map<String, String> map = new HashMap<String, String>(); ``` 2. **动态表单的特殊性** 若在 Struts 的 `DynaActionForm` 中使用 Map 属性,需通过: ```java // 使用表单内置的 map 属性[^2] form.get("propertyName"); ``` 而非直接操作 Map 实例 3. **常见错误模式** | 错误写法 | 正确写法 | 原因 | |---------|---------|------| | `map.put(key,value)` | `map.put("key","value")` | 字符串必须加双引号 | | `myMap.put(...)` | `map.put(...)` | 变量名不一致 | | `new HashMap<>()` | `new HashMap<String,String>()` | BeanShell泛型支持不足 | #### 🌐 相关案例验证 1. **JMeter 变量传递测试** ```java // 存储为JMeter变量 vars.put("myMap", map.toString()); // 在Debug Sampler中检查 ${myMap} ``` 2. **类型安全验证** ```java // 故意触发类型错误(测试泛型有效性) map.put(123, "数字键"); // ✅ 应编译报错,验证泛型生效 ``` #### 📚 延伸问题解决方案 1. **JSON转换优化** ```java // 使用Jackson库(需将jar放入JMeter/lib) ObjectMapper mapper = new ObjectMapper(); String json = mapper.writeValueAsString(map); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值