1.泛型和链表

1.泛型和链表

1.泛型

1.什么是泛型

1.英文含义:

​ generic paradigm一般类型

2.泛型的含义:

​ 泛型是一种未知的数据类型不像 int string 一样直接去内存中申请空间而是在确定泛型的类型的时候才会去申请内存空间。

3.应用场景:

​ 当我们不知道用什么类型的时候可以使用泛型。

4. 泛型的作用:

​ 泛型可以看作是一个变量 用来接收数据(像参数一样),接收的是一种类型

​ 案例:

​ T t—接收—>10

​ int t=10;

​ 提示:

​ <>号中的标识表示符是任意可以是任意字符、< T>

​ E的英文全拼是 element 元素

​ T的英文全拼是 Type 类型(自定义泛型)

​ 案例:

​ public static void func(T[]arr)

​ {

​ }

​ 注:

​ public static void func(T[]arr){}是一种模板可以用来存储一组数据然后返回一个自己想要的数据。

​ 案例:

​ 给你一组学生 返回学生中年龄最大的

​ 给你一堆苹果 返回苹果中最大的

5.经典脚本

​ public class ArrayList

​ {

​ public boolean add(E e)

​ public E get(int index )

​ }

​ 分析1:

​ 为什么动态数组可以作为泛型的典型案例呢?

​ 如果ArrayList不用泛型就无法存储自己想要存储的数据

​ 分析2:

​ 泛型可以当作参数和返回值

​ 当泛型出现在,o就表示一种类型了

​ 分析3:

​ 在什么情况下确定泛型的类型?

​ 1.泛型接口/类

​ 创建子对象或者对象的时候确定


在这里插入图片描述

​ 2.方法

​ 通过参数可以推断


在这里插入图片描述

2.泛型包含泛型的方法、泛型类、泛型接口

​ 1.泛型方法:

在这里插入图片描述

​ 2.泛型类:


在这里插入图片描述

​ 3.泛型接口:


在这里插入图片描述

3.泛型的好处:

1.避免类型转换带来的麻烦
案例:

​ public static void main05(String[] args) {

​ ArrayList list=new ArrayList<>();

​ list.add(1)

​ int number=list.get(0);

​ }

​ 案例:

​ public static void main05(String[] args) {

​ ArrayList list=new ArrayList<>();

​ //类型转换麻烦

​ list.add(1);

​ list.add(“1”);

​ list.add(1);

​ list.add(new Student(1,“1”));

​ int number=(int)list.get(0);

​ }

​ 注:存储什么类型 取出就是什么类型

2.把运行期异常代码 提前到了编译期

​ 案例:

​ 案例:

​ public static void main05(String[] args) {

​ ArrayList list=new ArrayList<>();

​ list.add(1);

​ list.add(“1”);

​ list.add(new Student(1,“1”))

​ int number=list.get(0);

​ }

​ 注:

​ 强烈建议不使用 ArrayList list=new ArrayList ();

​ 如果向list添加一些没有联系的一些数据时在查找数据的时候会变得非常麻烦尤其是在做增删改查的时候

4.泛型的弊端:

​ 只能存储固定类型的数据

5.自定义泛型方法和接口

​ 冒泡排序

​ 问题1:参加排序类型是固定的

​ 问题2:排序的条件是固定的

package CollectionDemo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;


import ExtendsDemo7.AirPlane;
import ExtendsDemo7.Dart;
import ExtendsDemo7.Hand;
import ExtendsDemo7.IThrowing;


/**
 * 集合
 * 
 * 
 * @author lenovo
 *
 */
public class CollectionTest {
	public static void main01(String[]args) {
		Collection<Integer> coll=new ArrayList<Integer>();
		Collection<Integer> coll2=new LinkedList<>();
		//接口指向实现类
		//接口不单单只指向一个实现类
		coll.add(1);//(多态)
		//重写完之后的add接口中的add是没有方法体的
		/**
		 * 接口中的都是抽象的只是定义了一个规范
		 * 
		 * 
		 * 
		 */
		coll.add(1);
		coll.add(2);
		if(coll.contains(1)) {//判断是否包含某个元素的
			System.out.println("包含1");
		}
		if(coll.isEmpty()) {
			System.out.println("空了");
		}
		//coll.remove(1);//移除一个元素
		//coll.clear();
		System.out.println(coll);
		coll.toArray();//把集合元素存储到数组
		//增强for循环
		//增强for循环的提示:
		//foreach-iterate over an array Iterable
		
		//循环for(要遍历的数据类型    变量名:要遍历的集合)
		//增强for循环与for循环相比  的区别:
		//不需要知道集合的长度而且看起来更加直观
		System.out.println("+++++++++++++++++");
		for(Integer integer:coll) {
			System.out.println(integer);
		}
		
	}
	public static void main02(String[]args) {
		int []arr= {1,2,3};
		for(int i:arr) {
			System.out.println(i);
			//问题:Hand  扔东西 
			    
		}
		Hand hand=new Hand();
		//创建一个手类
		hand.list=new ArrayList<>();
		//手类里边有一个集合然后初始化
		hand.list.add(new Dart(1000,100));
		hand.list.add(new AirPlane());
		//集合里边存储IThrowing类型的对象
		//集合里边存实现接口的对象
		hand.throwFunc();
		//想要实现迭代必须满足迭代的条件
		//第一步满足迭代的条件  实现接口Iterable 
		for(IThrowing i:hand) {
			System.out.println(i);
			//hand需要实现一个接口
		//只能通过 java.lang.Iterable 的数组或实例进行迭代	
			//hand没有实现iterate接口
		}
		//增强for循环的内部脚本
		//1.获取迭代器对象   对象指向数组
		Iterator<IThrowing>iterator=hand.iterator();
		//2.迭代器移动
		iterator.hasNext();//判断是否有下一个元素
//		if(iterator.hasNext()) {
//			IThrowing i=iterator.next();//获取迭代器上的数据
//		}
//		if(iterator.hasNext()) {
//			IThrowing i=iterator.next();//获取迭代器上的数据
//		}
//		if(iterator.hasNext()) {
//			IThrowing i=iterator.next();//获取迭代器上的数据
//		}
		//重复做一件事而且不知到循环次数
		while(iterator.hasNext()) {
			IThrowing i=iterator.next();
			System.out.println(i);
		}
		
	}
	//泛型
	public static void main03(String[]args) {
		int[]arr= {213};
		float[]arr1= {2,1,3};
		Arrays.parallelSort(arr);
		for(int i:arr) {
			System.out.println(i);
		}
		
	}
	public static<T>void sort3(T[]arr,Comparator<T>com){
		for(int i=0;i<arr.length-1;i++) {
			for(int j=0;j<arr.length-1;j++) {
				//number>0
				if(com.compare(arr[i], arr[i+1])>0){
					T temp=arr[i];
					arr[i]=arr[i+1];
					arr[i+1]=temp;
				}
			}
		}
	}
	public  static void main(String[]args) {
	Integer [] arr1 = {2,1,3};//int是基本数据类型不是clss  T 代表的是一种类型(int不是引用类型)
		
		Float []arr2= {1.0f,2.0f,3.0f};//泛型方法的T确定是通过参数推断出来的
		 Student s1=new Student(10,"1");
		 Student s2=new Student(18,"1");
		 Student s3=new Student(112,"1");
		 Student[]stuArr= {s1,s2,s3};
		 
		
		//sort(stuArr,new ComStudent());
		 sort3(stuArr,new Comparator<Student>() {

			@Override
			public int compare(Student t1, Student t2) {
				// TODO 自动生成的方法存根
				if(t1.age>t2.age) {
					return 1;
				}
				else if(t1.age<t2.age) {
					return -1;
				}
				else {
					return 0;
				}
			}
			   
			 
			 
			 
			 
			 
			 
		 });
		for(Student student :stuArr) {
			System.out.println(student.age);
		}
	} 
	public static<T>void sort(T[]arr,Comparator<T>com){
		for(int i=0;i<arr.length-1;i++) {
			for(int j=0;j<arr.length-1;j++) {
				if(com.compare(arr[i], arr[i+1])>0){
					T temp=arr[i];
					arr[i]=arr[i+1];
					arr[i+1]=temp;
				}
			}
		}
	}
}

package CollectionDemo;
/**
 * 
 * 
 * 泛型接口
 * 接口中会提供一个排序标准  对什么对象进行排序不知道
 * @author lenovo
 *
 * @param <T>
 */
public interface CompareHandler<T> {
    boolean compare(T t1,T t2); 
    	
    
	

}
class ComClass implements CompareHandler<Integer> {
	

	@Override
	public boolean compare(Integer t1, Integer t2) {
		if(t1>t2) {
			return true;
		}
		else {
			return false;
		}
		
	}
}
//class ComClass1 implements CompareHandler<Float>{
//	
//	public boolean compare(Float t1, Float  t2) {
//	 if(t1>t2) {
//		 return true;
//	 }
//	 else {
//		 return false;
//	 }
//  }
//
//	
//	
//}
class ComStudent implements CompareHandler<Student>{
	public boolean compare(Student t1,Student t2) {
		if(t1.age>t2.age) {
			return true;
		}
		else {
			return false;
		}
	}
}
package CollectionDemo;

public class Student {
   int age;
   private String name;
public int getAge() {
	return age;
}
public void setAge(int age) {
	this.age = age;
}
public String getName() {
	return name;
}
public void setName(String name) {
	this.name = name;
}
public Student(int age, String name) {
	super();
	this.age = age;
	this.name = name;
}
   
}

运行结果:

​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SrsFSbGw-1600951594116)(C:\Users\lenovo\Desktop\泛型\2020-09-24_161533.png)]
在这里插入图片描述

3.通用的排序方法

​ 1.任意类型的数组都可以参加排序

​ 2.指定任意的排序条件

​ 案例:

​ public static void sort(T [] arr,CompareHandler com){

​ //Arrays.sort

​ for (int i = 0; i < arr.length-1; i++) {

​ for (int j = 0; j < arr.length-1; j++) {

​ // 父类的引用调用子类的方法

​ if (com.compare(arr[i], arr[i+1])) {

​ T temp=arr[i];

​ arr[i]=arr[i+1];

​ arr[i+1]=temp;

​ }

​ }

​ }

​ }

​ 案例:

public static void main06(String[] args) {
		Integer [] arr={11,2,31};//int 基本数据类型 不是引用类型
		Float []  arr1={1.0f,2.0f,3.0f};
		Student s1=new Student(10, "1");
		Student s2=new Student(8, "1");
		Student s3=new Student(12, "1");
		Student [] stuArr={s1,s2,s3};
		//sort(stuArr, new ComStudent());
		
		sort3(stuArr, new Comparator<Student>() {

			@Override
			public int compare(Student o1, Student o2) {
				// TODO Auto-generated method stub
				if (o1.age>o2.age) {
					return 1;
				}
				else if (o1.age<o2.age) {
					return -1;
				}
				else {
					return 0;
				}
			}
			
			
		});
		for (Student student : stuArr) {
			System.out.println(student.age);
		}
	}
	
	public static <T> void  sort3(T [] arr,Comparator<T> com){
		//Arrays.sort
		for (int i = 0; i < arr.length-1; i++) {
			for (int j = 0; j < arr.length-1; j++) {
//              父类的引用调用子类的方法
				//number>0
				if (com.compare(arr[i], arr[i+1])>0) {
					T temp=arr[i];
					arr[i]=arr[i+1];
					arr[i+1]=temp;
				}
			}
		}
		
	}

6.泛型的规则:

  • 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前。
  • 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
  • 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
  • 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。

7.泛型的通配符

​ 当使用泛型类型或接口时,传递的数据,泛型类型不确定 可以使用通配符<?>表示

​ 缺点:

​ 一旦使用通配符之后 只能调用Object共性的方法了

​ 案例:

                    ```

package CollectionDemo;

import java.util.ArrayList;
import java.util.Collection;

public class GenericClassTest {
public static void main01(String[]args) {
GenericClass gene=new GenericClass<>();
gene.setMvp(“123”);
System.out.println(gene.toString());
}
public static void main(String[]args) {
Collectioncoll=new ArrayList<>();
Collection coll1=new ArrayList<>();

     getElement(coll);

}
public static void getElement(Collection<?>coll) {
//Collection<?>要的是固定集合的参数	

}

}

                    ```

注:

​ Collection和Collection<?>的的区别:

​ Collection的含义是不知道要操作的类型是什么要通过对象或者方法来确定,而Collection<?>是在 Collection<?>的前提之上知道了对象的类型想要获取对象的值并无需考虑对象的具体类型的时候即只要获取值的时候使用collection<?>

8.泛型约束

​ 1.泛型的上线

​ 格式:

​ 类型<? extends 类>对象名称

​ 含义:

​ ?必须要继承某一类型

​ 意义:

​ 只能接收该类型及其子类

​ 2.泛型的下线

​ 格式:

​ 类型<?super类>对象名称

​ 意义:

​ 只能接收该类型及其父类型

​ 案例:

                  ```

public static void main(String[]args) {
Collectioncoll=new ArrayList<>();
Collection coll1=new ArrayList<>();
Collectioncoll2=new ArrayList<>();
Collectioncoll3=new ArrayList<>();
getElement2(coll);//(访问了父类)//只能放Number及Number的子类
getElement2(coll2);//(访问了子类)
getElement2(coll3);//(访问了本身)
getElement3(coll);
getElement3(coll1);
getElement3(coll2);
getElement3(coll3);
getElement3(coll3);
//已知Object 所有类的父类
//String是一个普通类的引用类
//Integer类 继承自Number

}
//通配符美哟任何限制
public static void getElement(Collection<?>coll) {
//Collection<?>要的是固定集合的参数	

}
public static void getElement2(Collection<?extends Number>coll) {
	//Collection<?>要的是固定集合的参数	
	
	}
public static void getElement3(Collection<?super Number>coll) {
	//Collection<?>要的是固定集合的参数	
	
	}
                  ```

9.数据结构

​ 数据结构的意义:

​ 数据结构是判断一门编程好坏的标准之一

​ 常用的数据结构:

​ 线性数据结构:

​ 数组:

​ [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i5e2KtCe-1600951594117)(C:\Users\lenovo\Desktop\泛型\2020-09-24_173443.png)]
在这里插入图片描述

​ 链表:

在这里插入图片描述

​ 树:

在这里插入图片描述

​ 数组+树 表

​ 图:

在这里插入图片描述

​ 数组:(一块连续的区域)

​ int []arr

​ 优点:

​ 获取元素块

​ 动态数组:(牵一发而动全身)(一块连续的区域)

​ ArrayList

​ 动态数组的问题:

​ 没有解决数组插入/删除麻烦的问题

​ 链表:(牵一发而痛自己)

​ 链表:只要有能容易一个元素的内存就可以

​ 优点:

​ 链表的插入和删除的效率高

在这里插入图片描述

​ 缺点:

​ 获取元素效率低(每次都是从头开始找)

​ 查找链表:

​ 1.head头

​ 2.end 尾

​ 3.next(下一个)

​ next--------->next=(第一个元素)

​ 双向链表:


在这里插入图片描述

​ 链表的内部样式:
在这里插入图片描述

​ 案例:

package LinkedListDemo;
//链表
//ArrayList<E>
public class LinkedList<T> {
	   //长度
	   private int m_unsize=0;//只读

	public int getM_unsize() {
		return m_unsize;//只读的
	}
	//链表的头
	//链表的尾巴
    public  Node<T> m_head;//存储链表的头
	public  Node<T> m_end;//存储链表的尾
	//判空
	public boolean isEmpty() {
		return  m_head==null?true:false;
		//三元表达式判断链表为空
	}
	//添加
	public  void push_back(T data) {
		//给数据元素创建一个结点
		Node<T> pnewNode=new Node(data);
		if(isEmpty()) {
			m_head=pnewNode;//如果还没有元素让新元素作为头结点
			
		}else {
			m_end.setM_pNext(pnewNode);
			//不为空  设置尾、结点的下一个尾新结点
			m_unsize++;//长度+1
		}
		m_end=pnewNode;//更新新结点
	}
	//插入前插和后插
	public  boolean InserForward(T pdata,int pos) {
		if(isEmpty()) {
			System.out.println("空链表");
			return false;
		}
		//插入位置超出总链表长度
		else if(pos>=m_unsize) {
			System.out.println("去你的吧");
			return false;
		}
		if(pos==0) {//代表有一个头元素
			//如果插入位置为开始
			Node<T> pnewNode=new Node<>(pdata);
			pnewNode.setM_pNext(m_head);
			//设置新结点的下一个为原来的头结点
			m_head=pnewNode;
			m_unsize++;//更新头结点
		
			
		}
		else {
			Node<T>pFront=m_head;
			//记录的插入位置的上一个开始的时候是头结点
			 Node<T>ptemp=m_head;
			 //遍历的
			 int tempPos=1;
			 //更新位置   tempPos<pos
			 while(ptemp.getM_pNext()!=null&&tempPos<=pos ){
				 //获取插入位置上的结点和他的前结点
				 //因为要在插入位置的结点和他的前结点之间插入元素
				 pFront=ptemp;
				 ptemp=ptemp.getM_pNext();
				 tempPos++;
				 
			 }
			 //插入元素
			 Node<T>pnewNode=new Node<>(pdata);//插入数据的结点
			 pnewNode.setM_pNext(ptemp);
			 pFront.setM_pNext(pnewNode);
			 m_unsize++;
		}
		return true;
	}
	
	
	      

}


package LinkedListDemo;
//每一个结点可以看成一个类
//结点类   结点中存放着数据date和指向下一个结点的引用
public class Node<T> {
          private  T data;//需要保存的数据元素
          private Node<T> m_pNext;//后继结点的引用     下一个next结点
          private Node<T> m_pFront;//前驱节点的引用
		public T getData() {
			return data;
		}
		public void setData(T data) {
			this.data = data;
		}
		public Node<T> getM_pNext() {
			return m_pNext;
		}
		public void setM_pNext(Node<T> m_pNext) {
			this.m_pNext = m_pNext;
		}
		public Node<T> getM_pFront() {
			return m_pFront;
		}
		public void setM_pFront(Node<T> m_pFront) {
			this.m_pFront = m_pFront;
		}
		public Node() {
			this.data=null;
			 m_pFront=m_pNext=null;//两个引用设置为空
			    
			
		}
		
		
		public Node(T data) {
		
			this.data = data;//初始化数据
		    m_pFront=m_pNext=null;//两个引用设置为空
		    
		}
	
	
          
}

package LinkedListDemo;

public class Test {
	public static void main(String[]args) {
		LinkedList<Integer>list=new LinkedList<>();
		list.push_back(1);
		list.push_back(2);
		list.push_back(3);
		list.InserForward(100, 1);
		int number=list.m_head.getM_pNext().getData();
		int number2=list.m_end.getData();
		System.out.println(number);
		System.out.println(number2);
		
		
		
	}

}

data = data;
}
public Node getM_pNext() {
return m_pNext;
}
public void setM_pNext(Node m_pNext) {
this.m_pNext = m_pNext;
}
public Node getM_pFront() {
return m_pFront;
}
public void setM_pFront(Node m_pFront) {
this.m_pFront = m_pFront;
}
public Node() {
this.data=null;
m_pFront=m_pNext=null;//两个引用设置为空

	}
	
	
	public Node(T data) {
	
		this.data = data;//初始化数据
	    m_pFront=m_pNext=null;//两个引用设置为空
	    
	}

}


package LinkedListDemo;

public class Test {
public static void main(String[]args) {
LinkedListlist=new LinkedList<>();
list.push_back(1);
list.push_back(2);
list.push_back(3);
list.InserForward(100, 1);
int number=list.m_head.getM_pNext().getData();
int number2=list.m_end.getData();
System.out.println(number);
System.out.println(number2);

}

}


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1. `HashTable` 是 Java 中的一个哈希表实现,它继承自 `Dictionary` 类,实现了 `Map` 接口。`HashTable` 使用键值对的方式存储数据,其中键和值都是对象类型。 特点: - 线程安全:`HashTable` 是同步的,多线程环境下可以安全使用。 - 键值不允许为 null:`HashTable` 不允许使用 null 作为键或值,否则会抛出 NullPointerException。 - 哈希冲突解决:使用链表法解决哈希冲突,即在哈希表的每个位置上维护一个链表,当多个键映射到同一个位置时,将它们链接在一起。 2. `Collections` 是 Java 中提供的工具类,提供了一系列静态方法,用于操作集合(`Collection`)和地图(`Map`)。其中一些常用方法包括: - `sort()`:对集合进行排序。 - `binarySearch()`:在有序集合中执行二分查找。 - `reverse()`:反转集合中的元素顺序。 - `shuffle()`:随机打乱集合中的元素顺序。 - `max()`、`min()`:返回集合中最大或最小的元素。 - `addAll()`:将多个元素添加到集合中。 - `frequency()`:计算指定元素在集合中出现的次数。 3. 泛型是 Java 的一个特性,它允许在编译时指定集合中存储的元素类型。通过使用泛型,可以在编译时检查类型安全性,并减少在运行时出现类型转换错误的可能性。 在集合中使用泛型的作用: - 提供类型安全性:泛型可以防止将错误类型的对象放入集合中。 - 简化代码:避免了手动进行类型转换,使代码更加清晰和简洁。 - 提高性能:避免了运行时的类型检查和类型转换。 4. `? extends T` 是泛型通配符中的一种形式,表示可以接受 T 类型及其子类型的参数。这种通配符限制了具体的类型范围,可以用于声明方法参数、变量或返回值。 例如,`List<? extends Number>` 表示一个存储 Number 或其子类的列表,可以接受 Integer、Double 等具体类型的列表作为参数。 在使用 `? extends T` 通配符时,只能读取集合中的元素,不能添加新的元素到集合中。因为编译器无法确定具体的类型,只能确保从集合中读取的元素是 T 类型或其子类型。 5. `HashSet` 和 `HashMap` 都是 Java 中的集合类。 `HashSet` 是基于哈希表实现的无序集合,它使用哈希函数来计算元素的存储位置,具有快速的插入、删除和查找操作。`HashSet` 不允许重复元素,当尝试向 `HashSet` 中插入重复元素时,插入操作会被忽略。 `HashMap` 是基于哈希表实现的键值对存储结构。它也使用哈希函数来计算键的存储位置,可以通过键来快速查找对应的值。`HashMap` 允许键和值都为 null,并且允许重复的值。 在底层实现上,`HashSet` 实际上是通过一个 `HashMap` 来实现的,`HashSet` 的元素被存储为 `HashMap` 的键,而值则是一个常量对象。 6. `BigDecimal` 是 Java 中用于精确表示和计算大数字的类,提供了高精度的十进制计算。 `BigDecimal` 适用于需要高精度计算的场景,例如金融计算、货币计算等,可以避免使用浮点数导致的精度损失问题。 `BigDecimal` 的算术运算方法包括加法、减法、乘法、除法等,这些方法都是精确计算的,并且可以指定舍入模式来控制结果的精度和舍入方式。 例如,使用 `BigDecimal` 进行加法运算可以通过 `BigDecimal.add()` 方法实现: ```java BigDecimal num1 = new BigDecimal("10.25"); BigDecimal num2 = new BigDecimal("5.75"); BigDecimal sum = num1.add(num2); System.out.println(sum); // 输出: 16.00 ``` 在进行算术运算时,需要使用 `BigDecimal` 的方法进行操作,而不是直接使用运算符。这样可以确保精确的计算结果,并且可以灵活地控制舍入方式和精度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值