java学习笔记(3)数据类型、源码、反码、补码、精度损失、基本数据类型互相转换
关于java中的数据类型:
1、数据类型的作用是什么?
程序当中有很多数据,每一个数据都是有相关类型的,不同数据类型的数据占用的空间大小不同。
数据类型的作用是指导java虚拟机(JVM)在运行程序的时候给该数据分配多大的内存空间。
2、java中的数据类型包括两种:
*基本数据类型
*引用数据类型【后面说】
类、接口、数组......
3、关于基本数据类型:
*基本数据类型包括四大类八小种:
第一类:整数型
byte、short、int、long
第二类:浮点型
float、double
第三类:布尔型
boolean
第四类:字符型
char
说到这里想回顾一下javascript中的数据分为几种类型:基本类型:null、undefined、Boolean、number、string,引用类型:object、function、array.
4、字符串"abc"不属于基本数据类型,属于"引用数据类型"。字符属于基本数据类型
字符串使用双引号 "abc"
字符使用单引号 'a'
5、八种基本数据类型各自占用空间大小是多少?
| 类型描述 | 关键字 | 字节数 | 取值范围 | 默认值 |
| 字节型 | byte | 1个字节 | -27~27-1(-128~127) | 0 |
| 短整型 | short | 2个字节 | -215~215-1(-32768~32767) | 0 |
| 整型 | int | 4个字节 | -231~231-1(-2147483648~2147483647) | 0 |
| 长整型 | long | 8个字节 | -263~263-1(-9223372036854775808~9223372036854775807) | 0 |
| 单精度浮点型 | float | 4个字节 | 大约±3.40282347E+38F(有效位数6~7位) | 0.0f |
| 双精度浮点型 | double | 8个字节 | 大约±1.79769313486231570E+308(有效位数15位) | 0.0d |
| 字符型 | char | 2个字节 | 0~216-1(0~65535) | '\u0000' |
| 布尔型 | boolean | 1个字节 | true/false | false |
6、计算机在任何情况下都只能识别二进制。例如:只认识100101001010101010......
【现代计算机采用交流电的方式,接通和断开就两种状态,1:接通,0:断开】
7、什么是二进制?
*数据的一种表示形式,十进制表示满10进1原则,二进制表示满2进1原则。
例如:十进制:0、1、2、3、4、5、6、7、8、9、10、11、12、13、14、15、16、17、18、19、20
二进制:0、1、10、11、100、101、110、111、1000、1001、1010、、、、、、、、、、、、、、
8、字节(byte):
1Byte=8bit 【1个字节=8个比特单位】,1bit(1个比特位就是一个1或者一个0)
1KB=1024Byte
1MB=1024KB
1GB=1024MB
1TB=1024GB
9、整数型当中的byte类型,占用一个字节,所以byte类型的数据占用8个bit(比特位)。那么byte类型的取值范围是什么?
*关于java中的数字类型,数字都是由正负之分的,所以在数字的二进制当中,有一个二进制位,被称为"符号位"。并且这个"符号位",在所有二进制位的最左边。
0表示正数,1表示负数。
*byte类型最大值:01111111【10000000(二进制)-1】=【27-1】=127
*byte类型的最小值是-128
*byte的取值范围是【-128~127】
*byte类型可以表示256种不同的二进制
10、二进制和十进制之间的抓换规则:
*二进制转换成十进制 (从右向左,小数点后从左向右)
10010=0*20+1*21+0*22+0*23+1*24 =18
*十进制转换成二进制
7=1*22+1*21 +0*20 7=110
11、计算机只认识二进制,那么计算机是怎么表示现实生活中的文字的呢?
*八种数据类型当中,byte,short,int,long,float,double,boolean这7种数据类型,计算机在表示的时候比较容易,因为底层都是数字,因为十进制的数字和二进制之间存在一种固定的转换规则。
*但是八种数据类型中,char类型表示的是现实生活中的文字,文字和计算机二进制之间默认是不存在任何转换关系的。
*为了让二进制可以表示现实世界中的文字,我们需要进行人为的干涉,需要人提前制定好"文字"和"二进制"之间的对照关系。这种对照转换关系被称为"字符编码"。
*计算机最初只支持英文,最先出现的是ASCII码(阿斯可)。
'a'--->97 【01100001】
'A'--->65
'0'--->48
'a'--->(按照ASCII解码)--->【01100001】
01100001--->(按照ASCII编码)--->'a'
编码和解码的时候采用同一套字典/对照表,不会出现乱码。
当解码和编码的时候采用的不是同一套对照表,就会出现乱码。
*随着计算机语言的发展,后来出现一种编码方式,是国际化标准组织ISO制定的,这种编码方式支持西欧语言,向上兼容ASCII码,仍然不支持中文,这种编码方式是ISO-8859-1,又被称为lating-1,
*随着计算机向亚洲发展,计算机开始支持中文,日文,韩文等国家文字,其中支持简体中文的编码当时有:
GB2312/GBK/GB18030 他们的容量是从小到大
*支持繁体中文的:大五码(big5)
*后来出现了一种编码方式统一了全球的文字:容量较大,这种编码方式叫作:unicode编码。
unicode编码方式有多种具体的实现:
------UTF-8
------UTF-16
------UTF-32
......
*java语言采用的是哪一种编码方式呢?
-java语言源代码采用的是unicode编码方式,所以"标识符"可以用中文。
*现在在实际开发中,使用UTF-8编码方式较多。【统一编码方式】
12、八种基本数据类型的取值范围:
类型 取值范围
----------------------------------------------------
byte 【-128~127】
short 【-32768~32767】
int 【-2147483648~2147483647】
long 【-9223372036854775808~9223372036854775807】
float 【大约±3.40282347E+38F(有效位数6~7位)】
double 【大约±1.79769313486231570E+308(有效位数15位)】
boolean 【true/false】
char 【0~65535】
注意:short和char所表示的种类总数是一样的,只不过char可以表示更大的正整数,因为char没有负数。
/* 关于八种基本数据类型的默认值: 数据类型 默认值 ---------------------------------------- byte,short,int,long 0 float,double 0.0 boolean false 【在c语言中:true:1 false:0】 char \u0000 【 八种基本数据类型的默认值一切向0看齐 */ public class DataTypeTest02{ //这里的static 必须加,别问为什么。后面再说 static int k = 1000; // 变量还是遵守这个语法:变量必须先声明再赋值才能访问。 // 成员变量没有手动赋值,系统会默认赋值。【局部变量不会】 static int f;//成员变量 public static void main(String[] args){ // int i; // System.out.println(i);//局部变量 System.out.println(k); System.out.println(f);//0 } }
回顾一下编译与运行命令:编译:javac 源码路径(强制utf-8编码:javac -encoding UTF-8 源码路径)
运行:java 编译好的类名
java数据类型详解:
char(字符型):
public class DataTypeTest01{ public static void main(String[] args){ // 定义一个char类型的变量,起名c,同时赋值字符'a' char c = 'a'; System.out.println(c); // 一个中文占用两个字节,char类型正好是两个字节 // 所以java中的char类型变量可以存储一个中文字节,两个以上是不行的,会报错 char x = '国'; System.out.println(x); // 编译错误 // ab是字符串,不能使用单引号括起来 // char y = 'ab'; // "a"是字符串类型,因为是用双引号括起来的 // k变量是字符类型 // 类型不兼容,编译错误 // char k = "a"; // 声明 char e; // 赋值 e = 'e'; System.out.println(e);//e // 再次赋值 e = 'f'; System.out.println(e);//f } }
关于java语言中的char类型:
转义字符
/* 关于java语言中的char类型 转义字符 : \ 反斜杠 转义字符出现在特殊字符之前,会将特殊字符转义成普通字符 \n 换行符 \t 制表符 \\ 普通的反斜杠 \' 普通的单引号 \" 普通的双引号 补充一下十六进制和八进制 十进制:满10进一位 0 1 2 3 4 5 6 7 8 9 10 11 12 13 ...... 二进制:满2进一位 0 1 10 11 100 101 1000 1001 10000 10001...... 十六进制:满16进一位 0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 八进制:满8进一位 0 1 2 3 4 5 6 7 10 12 13 14 15 16 17 20...... */ public class DataTypeTest01{ public static void main(String[] args){ // 普通的n字符 char c1 = 'n'; System.out.println(c1); // 依照目前所学知识,以下程序无法编译通过,因为显然是一个字符串,不能使用单引号括起来 // 但是经过编译,发现编译通过了,这说明,以下并不是一个字符串,而是"一个"字符; // 这是一个"换行符",属于char类型的数据 // 反斜杠在java语言当中具有转义功能。 char c2 = '\n';// \n是换行符 System.out.println(c2);//并看不到 // 如何能看到换行符的效果? // 以下打印出来的两个字符串时换行显示的 System.out.println("Hello"); System.out.println("World!"); //这里print没有带上后面的ln,而以下打印出来的两个字符串时连接起来的,说明ln具有换行功能 // println:表示输出之后换行 print:表示输出之后不换行 System.out.print("Hello"); System.out.println("World!"); // 下面看一下\n的效果 // 返现以下AB换行显示了 System.out.print("A"); System.out.print('\n'); System.out.println("B"); char x = 't'; System.out.println(x);//t // \t 是制表符 相当于键盘上的tab键 tab同样可以让字符隔开,看着像空格,但是它和空格的ASCII码不一样,需要区分开 char y = '\t'; System.out.println(y);//没看到输出东西 System.out.print("A"); System.out.print(y); System.out.println("B");//发现AB并不是连续出现的,这两个字母中间有很大的空格,这是\t的作用 // 那么怎样在控制台上输出反斜杠\呢? // 以下是不行的,编译会报错 // 原因是反斜杠将后面的单引号转义成不具备特殊含义的特殊单引号字符,所以左边的单引号缺少了结束的单引号字符 // char k = '\'; // System.out.println(k); // 下面这样输出,前面的反斜杠将后面的反斜杠转义成了不具备特殊含义的反斜杠,这样控制台就能输出\了 // 结论:在java语言当中两个反斜杠\\,代表一个普通的反斜杠字符\ char k = '\\'; System.out.println(k);// \ // 怎么在控制台上输出一个普通的单引号字符' // char a = '';//java中不允许这样编写程序,编译会报错 // char a = ''';//这样也会报错,因为第一个单引号和第二个配对了,第三个单引号没有配对,所以报错 char a = '\''; System.out.println(a);// ' char f ='"'; System.out.println(f);//这样不会报错,因为单引号中间只是一个普通的双引号字符 System.out.println("“hello world”");//“hello world” System.out.println("\"hello world\"");//"hello world" char m = '中'; System.out.println(m); // JDK中自带的native2ascii.exe命令,可以将文字转换成unicode编码形式 // 在DOS窗口中国输入native2ascii 命令 回车 // 然后输入文字 回车后可以出现对应的unicode编码 // 反斜杠u:后面的一串数字就是文字的unicode编码 char n = '\u6211';//'我'对应的unicode编码是6211 System.out.println(n);//我 } }
整数型
byte short int long
/* 关于java语言当中的整数型: 数据类型 占用空间大小 默认值 取值范围 --------------------------------------------- byte 1 0 -128~127 short 2 0 -32768~32767 int 4 0 -2147483648~2147483647 long 8 0L 1、java中的"整数型字面值"被当做int类型来处理。如果要让"整数型字面值"被当做long类型来处理的话, 需要在"整数型字面值"后面加上l或L,建议使用大写的L。 2、java语言当中整数型字面值有3中表示方式: 第一种方式:十进制【是一种缺省默认的方式】 第二种方式:八进制【在编写八进制字面值的时候需要以0开始】 第三种方式:十六进制【在编写十六进制整数型字面值的时候需要以0x开始】 */ public class DataTypeTest04{ public static void main(String[] args){ int a = 10;//十进制 int b = 010;//整数型字面值以0开始的,后面那一串数字就是八进制 int c = 0x10;//整数型字面值以0x开始的,后面那一串数字就是十六进制 System.out.println(a);//10 System.out.println(b);//8 System.out.println(c);//16 System.out.println(a+b+c);//34 // 123这个整数型字面值是int类型 // i变量声明的时候,也是int类型 // int类型的123赋值给int类型的变量i,不存在类型转换 int i = 123; System.out.println(i); // 456整数型字面值是int类型,占用4个字节 // x变量在声明时是long类型,占用8个字节 // int类型的字面值456,赋值给long类型的变量x,存在类型转换 // int类型转换成long类型 // int类型是小容量,long类型是大容量 // 小容量可以自动转换成大容量,称为自动类型转换机制。 long x = 456; System.out.println(x);//456 // 2147483647是int类型,占用4个字节 // y变量是long类型,占用8个字节,自动类型转换 long y = 2147483647; System.out.println(y);//2147483647 // 编译错误:过大的整数:2147483648 // long z = 2147483648;//2147483648已经超出int类型的取值范围 // 解决错误 // 2147483648字面值一上来就当做long类型来处理,在字面值后面添加L // 2147483648L是占用8个字节的long类型 // z是long类型的变量,以下程序不存在类型转换 long z = 2147483648L; System.out.println(z);//2147483648 } }
/* 关于java语言当中的整数型 byte short int long */ public class DataTypeTest04{ public static void main(String[] args){ // 100L是long类型字面值 // x是long类型变量 // 不存在类型转换直接赋值 long x = 100L; // x是long类型,占用8个字节 // y是int类型,占用4个字节 // 以下程序可以编译通过吗? // 编译错误:大容量不能直接赋值给小容量,可能会有精度损失 // int y = x; // 大容量赋值给小容量,需要进行强制类型转换 // 需要加"强制类型转换符" // 加上"强制类型转换符"之后,编译可以通过,但是运行阶段可能存在精度损失。 // 所以强制类型转换谨慎使用,因为损失精度之后,可能损失很严重 // 强制转换原理: // 原始数据(long):00000000 00000000 00000000 00000000 00000000 00000000 00000000 01100100 // 强转之后的数据(int):00000000 00000000 00000000 01100100 // 将左边的二进制砍掉【所有的数据强转的时候都是这样完成的】 int y = (int)x; System.out.println(y);//100 // 原始数据(long):00000000 00000000 00000000 00000000 10000000 00000000 00000000 00000000 // 强转之后的数据(int):10000000 00000000 00000000 00000000 // 10000000 00000000 00000000 00000000目前存储在计算机内部,计算机内部都是采用补码的形式存储 // 所以10000000 00000000 00000000 00000000现在是一个补码形式 // 将以上的补码转换成源码就是最终的结果 long k = 2147483648L; int e = (int)k; System.out.println(e);//-2147483648 本来是正数强转之后变成负数了 精度损失非常严重 // 分析以下程序是否可以编译通过? // 依据目前所学知识,以下程序时候无法编译通过的 // 理由:50是int类型的字面值,b是byte类型的变量 // 显然是大容量int转换成销容量byte // 大容量转换小容量是需要添加强制类型转换符的,以下代码并未添加,按理说编译应该报错。 // 但是在实际编译的时候,并没有报错,这说明:在java语言当中,当一个整数型字面值没有超出byte类型的取值范围的话,该字面值可以直接赋值给byte类型的变量。 byte b = 50; System.out.println(b);//50 未编译报错 byte c = 127; System.out.println(c);//127 未编译报错 // byte d = 128; // System.out.println(d);//编译报错 不兼容的数据类型 因为128已经超出了byte类型的取值范围 // 纠正错误 // 需要使用强制类型转换符, // 但是一定会损失精度 // 原始数据:00000000 00000000 00000000 10000000 // 强转之后的数据:10000000 【这是存储在计算机内部的,这是一个补码,它的源码是什么?】 byte d = (byte)128; System.out.println(d);//-128 } }
介绍一下,源码、反码、补码
要想理解原码, 反码和补码的概念, 需要先了解机器数和真值的概念. 1、机器数 一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1. “比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。 那么,这里的 00000011 和 10000011 就是机器数。” 2、真值 因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数 10000011,其最高位1代表负,其真正数值是 -3 而不是形式值131(10000011转换成十进制等于131)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。 “例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1” 3.原码 原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制: “[+1]原 = 0000 0001 [-1]原 = 1000 0001” 4.反码 反码的表示方法是: 正数的反码是其本身 负数的反码是在其原码的基础上, 符号位不变,其余各个位取反. [+1] = [00000001]原 = [00000001]反 [-1] = [10000001]原 = [11111110]反 一般我们要把反码转换成源码才能看懂。 5. 补码 补码的表示方法是: 正数的补码就是其本身 负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1) [+1] = [00000001]原 = [00000001]反 = [00000001]补 [-1] = [10000001]原 = [11111110]反 = [11111111]补 对于负数, 补码表示方式也是人脑无法直观看出其数值的. 通常也需要转换成原码在计算其数值.
注意:补码的补码就是源码
计算机二进制有3种表示形式:
源码,反码,补码
计算机在任何情况下底层表示和存储数据的时候采用的补码形式。
例如:补码转源码和源码转补码过程时一样的
补码:10000000----》反码:11111111----》源码:00000001 10000000-----》-128
例2:byte m = (byte)198;这样强类型转换后,输出的是-58,下面看看精度是如何损失的。
198----》二进制:00000000 00000000 00000000 11000110(原始数据)----》强类型转换后-----》11000110(注意,它现在在计算机中存储,是一个补码)----》
转换成反码:10111001----》转换成源码:10111010----》转换成数值:-58
// 如果int类型的字面值没有超过short类型的取值范围也可以直接赋值 short s = 32767;//编译通过 // short s1 = 32768;//编译报错 超出了short类型的取值范围 // 如果int类型的字面值没有超出short的取值范围,也可以直接赋值 char cc = 65535;//编译通过 // char cc1 = 65536;//编译失败,超出了char的取值范围 // 总结:当一个整数字面值没有超出byte、short、char的取值范围时,这个字面量可以直接赋值给类型为byte、short、char类型的变量。
这种机制是SUN公司允许的,目的是方便程序员编程
浮点型:float、double
/* 关于浮点型数据类型 float 单精度 【4个字节】 double 双精度 【8个字节,精度较高】 但是对于财务来说精度还是不够 财务要就的精度 double无法满足怎么办? 打开java/jre/lib/rt.jar 打开文件后/java/math/bigDecimal.class这个精度是非常高的 财务涉及到钱的问题,要求精度较高,所以SUN在基础SE类库当中为程序员准备了精度更高的类型, 只不过这种类型是一种引用数据类型,不属于基本数据类型,它是:java.math.BigDecimal 其实java程序中SUN提供了一套庞大的类库,java程序员是基于这套基础的类库来进行开发的。 所以要知道java的SE类库的字节码文件在哪儿? 要知道java的SE类库的源码在哪? *SE类库字节码:java/JDK/jre/lib/rt.jar *SE类库源码:java/JDK/src.zip 例如:String.java和String.class 我们的(String[] args)的String使用的就是String.class字节码文件 在java语言中,所有的浮点型字面值【3.0】,默认的被当做double类型来处理。 要想该字面值当做float类型来处理,需要在字面值后面添加F或f 注意:double和float在计算机内部二进制存储的时候存储的都是近似值。 在现实世界当中,有些数字是无限循环的。例如3.3333333...... 计算机的资源时有限的,用有限的资源存储无限的数据,只能存储近似值 */ public class DataTypeTest04{ public static void main(String[] args){ // 3.0是double类型的字面值 // d是double类型的变量 // 不存在类型转换 double d = 3.0; System.out.println(d); // 5.1是double类型的字面值 // f是float类型都的变量 // 大容量转换为小容量需要加强制类型转换符,所以以下程序编译错误。 // float f = 5.1; // 解决方案 // 第一种方式:强制类型转换 float f = (float)5.1; System.out.println(f);//5.1 // 第二种方式:没有类型转换 float f1 = 5.1f; System.out.println(f1);//5.1 } }
学习java的书籍推荐:java核心技术卷一、卷二。 java编程思想。等
布尔型:boolean
/* 关于布尔数据类型:boolean 在java语言中boolean类型只有两个值:true/false 默认是false 不像C语言中,0和1可以表示假和真 在底层存储的时候,boolean类型占用一个字节。 因为实际存储的时候,false是0,true是1。 布尔类型在实际开发中非常重要,使用频率较高。 经常使用在逻辑运算和流程控制语句当中。 */ public class DataTypeTest04{ public static void main(String[] args){ // 不兼容的类型,编译错误 // boolean flag = 1; // if语句 叫条件控制语句 boolean loginSuccess = true; if(loginSuccess){ System.out.println("恭喜您,登录成功"); }else{ System.out.println("用户名不存在或者密码错误"); } } }
基本数据类型互相转换:
/* 基本数据类型的互相转换:转换规则 1、8中基本数据类型当中,除boolean类型之外都可以互相转换; 2、小容量向大容量转换,称为自动类型转换,容量从小到大排序: byte<short<int<long<float<double char< 注意:任何浮点类型不管占用多少个字节都比整数型容量大。 char和short可表示的种类总数量相同,但是char可以表示更大的正整数 3、大容量转换小容量,叫作强制类型转换,需要加强制类型转换符,程序才能编译通过, 但是在运行阶段可能会损失精度,所以谨慎使用。 4、当整数字面值没有超出byte、short、char的取值范围,可以直接赋值给char、short,byte类型的变量。 5、byte、short、char做混合运算的时候,各自先转换成int类型再做运算。 6、多种数据类型混合运算,先转换成容量最大的那种类型再做运算。 注意: byte b = 3;可以编译通过,3没有超过byte类型的取值范围。 int i = 10; byte c = i/3;//编译报错,编译器只会检查语法,不会运算 i/3 */ public class DataTypeTest04{ public static void main(String[] args){ // 出现错误,1000超出了byte的范围 // byte a = 1000; // 正确,因为20没有超过byte的范围 byte a = 20; // 变量不能重名 // short a = 1000; // 正确,因为1000没有查出short的取值范围 short b = 1000; // 正确,因为默认就是int类型,并且没有超出int类型的范围 int c = 1000; // 正确,可以自动转换 long d = c; // 错误,出现精度丢失问题,大类型---》小类型会出现问题 // int e = d; // 将long强制转换成int类型 // 因为1000没有超出int范围,所以转换是正确的 int e = (int)d; // 因为java中的运算会转换成最大类型 // 而10和3默认是int,所以运算后的最大类型也是int // 所以是正确的 int f = 10/3;//10除以3 结果为3 // 声明10位long的类型 long g = 10; // 出现错误,多个类型运算过程中,会转换成容量最大的类型。 // 以下示例,最大的类型为double,而h为int,所以就会出现大类型(long)到小类型(int)的转换,会出现精度损失 // int h = g/3; // 可以强制转换,以为运算结果没有超出int范围。 // int h = (int)g/3; // 可以采用long类型来接收运算结果。 long h = g/3; // 出现精度损失问题,以下问题主要是优先级的问题。 // 将long类型的g转换成int,然后又将int类型的g转换成byte,最后byte类型的g与3运算, // 那么它的运算结果类型就是int,所以int赋值给byte就出现了精度损失问题。 // byte h = (byte)(int)g/3;//编译期只检查语法不进行运算,所以跟上表达式就错了。 // 正确 // byte h = (byte)(int)(g/3); // 不能转换,还有因为优先级的问题;(在编译之前g并未转换成byte类型,g还是long类型) // byte h = (byte)g/3; // 可以转换,因为int结果没有超出short范围 // short h = (short)(g/3); short i = 10; byte j = 5; // 错误,short和byte运算首先会转换成int再运算 // 所以运算结果为int,int赋值给short会出现精度丢失问题; // short k = i + j; // 可以将计算结果强制转换成short // short k = (short)(i + j); // 因为运算结果为int,所以可以用int类型接收 int k = i + j; char l = 'a'; System.out.println(l);//a // 输出结果为97,也就是a的ascii值; System.out.println((byte)l);//97 int m = l + 100; // 输出结果为197,取得a的ascii码的值,然后与100进行相加运算。 System.out.println(m);//197 double dd = 10 / 3; System.out.println(dd);//3.0 dd = 10.0 / 3; System.out.println(dd);//3.33333333333335 } }

浙公网安备 33010602011771号