做网站怎么能在百度搜索到,网站集约化建设难点,北京网站制作的,做环评工作的常用网站一前言
由于我们的重点是数据结构与算法#xff0c;所以我会快速的将JAVA 基础知识过一遍#xff0c;而且有了c语言的基础JAVA是很好学的。
二主要内容
本节我们将介绍Java程序的基础知识#xff0c;包括#xff1a; Java程序基本结构
我们先剖析一个完整的Java程序所以我会快速的将JAVA 基础知识过一遍而且有了c语言的基础JAVA是很好学的。二主要内容本节我们将介绍Java程序的基础知识包括Java程序基本结构我们先剖析一个完整的Java程序它的基本结构是什么/** * 可以用来自动创建文档的注释 */ public class Hello { public static void main(String[] args) { // 向屏幕输出文本: System.out.println(Hello, world!); /* 多行注释开始 注释内容 注释结束 */ } } // class定义结束因为Java是面向对象的语言一个程序的基本单位就是classclass是关键字这里定义的class名字就是Hellopublic class Hello { // 类名是Hello // ... } // class定义结束类名要求类名必须以英文字母开头后接字母数字和下划线的组合习惯以大写字母开头这里和c语言不一样但是答题一致要注意遵守命名习惯好的类命名HelloNoteBookVRPlayer不好的类命名helloGood123Note_Book_World注意到public是访问修饰符表示该class是公开的。不写public也能正确编译但是这个类将无法从命令行执行。在class内部可以定义若干方法method这个算是特有的了public class Hello { public static void main(String[] args) { // 方法名是main // 方法代码... } // 方法定义结束 }方法定义了一组执行语句方法内部的代码将会被依次顺序执行。这里的方法名是main返回值是void表示没有任何返回值。我们注意到public除了可以修饰class外也可以修饰方法。而关键字static是另一个修饰符它表示静态方法后面我们会讲解方法的类型目前我们只需要知道Java入口程序规定的方法必须是静态方法方法名必须为main括号内的参数必须是String数组。方法名也有命名规则命名和class一样但是首字母小写好的方法命名maingoodMorningplayVR不好的方法命名Maingood123good_morning_playVR在方法内部语句才是真正的执行代码。Java的每一行语句必须以分号结束public class Hello { public static void main(String[] args) { System.out.println(Hello, world!); // 语句 } }在Java程序中注释是一种给人阅读的文本不是程序的一部分所以编译器会自动忽略注释。Java有3种注释第一种是单行注释以双斜线开头直到这一行的结尾结束// 这是注释...而多行注释以/*星号开头以*/结束可以有多行/* 这是注释 blablabla... 这也是注释 */还有一种特殊的多行注释以/**开头以*/结束如果有多行每行通常以星号开头/** * 可以用来自动创建文档的注释 * * auther liaoxuefeng */ public class Hello { public static void main(String[] args) { System.out.println(Hello, world!); } }这种特殊的多行注释需要写在类和方法的定义处可以用于自动创建文档。Java程序对格式没有明确的要求多几个空格或者回车不影响程序的正确性但是我们要养成良好的编程习惯注意遵守Java社区约定的编码格式。最好还是按格式因为看的很舒服我们班有些初学者的代码看的我头疼具体的代码格式要求可以在Eclipse的设置中Java-Code Style查看变量和数据类型在Java中变量分为两种基本类型的变量和引用类型的变量。我们先讨论基本类型的变量。在Java中变量必须先定义后使用在定义变量的时候可以给它一个初始值。例如int x 1;上述语句定义了一个整型int类型的变量名称为x初始值为1。不写初始值就相当于给它指定了默认值。默认值总是0。来看一个完整的定义变量然后打印变量值的例子// 定义并打印变量 public class Main { public static void main(String[] args) { int x 100; // 定义int类型变量x并赋予初始值100 System.out.println(x); // 打印该变量的值 } }变量的一个重要特点是可以重新赋值。例如对变量x先赋值100再赋值200观察两次打印的结果// 重新赋值变量 public class Main { public static void main(String[] args) { int x 100; // 定义int类型变量x并赋予初始值100 System.out.println(x); // 打印该变量的值观察是否为100 x 200; // 重新赋值为200 System.out.println(x); // 打印该变量的值观察是否为200 } }注意到第一次定义变量x的时候需要指定变量类型int因此使用语句int x 100;。而第二次重新赋值的时候变量x已经存在了不能再重复定义因此不能指定变量类型int必须使用语句x 200;。变量不但可以重新赋值还可以赋值给其他变量。让我们来看一个例子// 变量之间的赋值 public class Main { public static void main(String[] args) { int n 100; // 定义变量n同时赋值为100 System.out.println(n n); // 打印n的值 n 200; // 变量n赋值为200 System.out.println(n n); // 打印n的值 int x n; // 变量x赋值为nn的值为200因此赋值后x的值也是200 System.out.println(x x); // 打印x的值 x x 100; // 变量x赋值为x100x的值为200因此赋值后x的值是200100300 System.out.println(x x); // 打印x的值 System.out.println(n n); // 再次打印n的值n应该是200还是300 }这和c语言都一样我就精简一点基本数据类型基本数据类型是CPU可以直接进行运算的类型。Java定义了以下几种基本数据类型大部分和从都一样如果没学过c语言的可以看我上一篇文字有廖雪峰老师的原文档整数类型byteshortintlong浮点数类型floatdouble字符类型char布尔类型booleanJava定义的这些基本数据类型有什么区别呢要了解这些区别我们就必须简单了解一下计算机内存的基本结构。计算机内存的最小存储单元是字节byte一个字节就是一个8位二进制数即8个bit。它的二进制表示范围从00000000~11111111换算成十进制是0~255换算成十六进制是00~ff。内存单元从0开始编号称为内存地址。每个内存单元可以看作一间房间内存地址就是门牌号。0 1 2 3 4 5 6 ... ┌───┬───┬───┬───┬───┬───┬───┐ │ │ │ │ │ │ │ │... └───┴───┴───┴───┴───┴───┴───┘我们在这里详解c语言没有的或者是不常见的。intfloat我就不过多赘述了布尔类型布尔类型boolean只有true和false两个值布尔类型总是关系运算的计算结果boolean b1 true; boolean b2 false; boolean isGreater 5 3; // 计算结果为true int age 12; boolean isAdult age 18; // 计算结果为falseJava语言对布尔类型的存储并没有做规定因为理论上存储布尔类型只需要1 bit但是通常JVM内部会把boolean表示为4字节整数。引用类型除了上述基本类型的变量剩下的都是引用类型。例如引用类型最常用的就是String字符串String s hello;引用类型的变量类似于C语言的指针它内部存储一个“地址”指向某个对象在内存的位置后续我们介绍类的概念时会详细讨论常量有点像宏定义定义变量的时候如果加上final修饰符这个变量就变成了常量final double PI 3.14; // PI是一个常量 double r 5.0; double area PI * r * r; PI 300; // compile error!常量在定义时进行初始化后就不可再次赋值再次赋值会导致编译错误。常量的作用是用有意义的变量名来避免魔术数字Magic number例如不要在代码中到处写3.14而是定义一个常量。如果将来需要提高计算精度我们只需要在常量的定义处修改例如改成3.1416而不必在所有地方替换3.14。为了和变量区分开来根据习惯常量名通常全部大写。var关键字有点像c中的结构体有些时候类型的名字太长写起来比较麻烦。例如StringBuilder sb new StringBuilder();这个时候如果想省略变量类型可以使用var关键字var sb new StringBuilder();编译器会根据赋值语句自动推断出变量sb的类型是StringBuilder。对编译器来说语句var sb new StringBuilder();实际上会自动变成StringBuilder sb new StringBuilder();因此使用var定义变量仅仅是少写了变量类型而已。整数运算ava的整数运算遵循四则运算规则可以使用任意嵌套的小括号。四则运算规则和初等数学一致。例如// 四则运算 public class Main { public static void main(String[] args) { int i (100 200) * (99 - 88); // 3300 int n 7 * (5 (i - 9)); // 23072 System.out.println(i); System.out.println(n); } }整数的数值表示不但是精确的而且整数运算永远是精确的即使是除法也是精确的因为两个整数相除只能得到结果的整数部分int x 12345 / 67; // 184求余运算使用%int y 12345 % 67; // 12345÷67的余数是17溢出直接用更大的的数据类型即可longlonglong没多占多少内存要特别注意整数由于存在范围限制如果计算结果超出了范围就会产生溢出而溢出不会出错却会得到一个奇怪的结果// 运算溢出 public class Main { public static void main(String[] args) { int x 2147483640; int y 15; int sum x y; System.out.println(sum); // -2147483641 } }要解释上述结果我们把整数2147483640和15换成二进制做加法0111 1111 1111 1111 1111 1111 1111 1000 0000 0000 0000 0000 0000 0000 0000 1111 ----------------------------------------- 1000 0000 0000 0000 0000 0000 0000 0111由于最高位计算结果为1因此加法结果变成了一个负数。特别注意整数的除法对于除数为0时运行时将报错但编译不会报错。其余还剩自增自减位移运算位运算都与c语言一致我就不讲了运算优先级这个在c中算是一个容易混淆的知识点在Java的计算表达式中运算优先级从高到低依次是()!~--*/%-|-*/记不住也没关系只需要加括号就可以保证运算的优先级正确。浮点数运算浮点数运算和整数运算相比只能进行加减乘除这些数值计算不能做位运算和移位运算。在计算机中浮点数虽然表示的范围大但是浮点数有个非常重要的特点就是浮点数常常无法精确表示。举个例子浮点数0.1在计算机中就无法精确表示因为十进制的0.1换算成二进制是一个无限循环小数很显然无论使用float还是double都只能存储一个0.1的近似值。但是0.5这个浮点数又可以精确地表示。因为浮点数常常无法精确表示因此浮点数运算会产生误差// 浮点数运算误差 public class Main { public static void main(String[] args) { double x 1.0 / 10; double y 1 - 9.0 / 10; // 观察x和y是否相等: System.out.println(x); System.out.println(y); } }由于浮点数存在运算误差所以比较两个浮点数是否相等常常会出现错误的结果。正确的比较方法是判断两个浮点数之差的绝对值是否小于一个很小的数// 比较x和y是否相等先计算其差的绝对值: double r Math.abs(x - y); // 再判断绝对值是否足够小: if (r 0.00001) { // 可以认为相等 } else { // 不相等 }浮点数在内存的表示方法和整数比更加复杂。Java的浮点数完全遵循IEEE-754标准这也是绝大多数计算机平台都支持的浮点数标准表示方法。布尔运算对于布尔类型boolean永远只有true和false两个值。布尔运算是一种关系运算包括以下几类比较运算符!与运算或运算||非运算!下面是一些示例boolean isGreater 5 3; // true int age 12; boolean isZero age 0; // false boolean isNonZero !isZero; // true boolean isAdult age 18; // false boolean isTeenager age 6 age 18; // true关系运算符的优先级从高到低依次是!!||短路运算布尔运算的一个重要特点是短路运算。如果一个布尔运算的表达式能提前确定结果则后续的计算不再执行直接返回结果。因为false x的结果总是false无论x是true还是false因此与运算在确定第一个值为false后不再继续计算而是直接返回false。我们考察以下代码// 短路运算 public class Main { public static void main(String[] args) { boolean b 5 3; boolean result b (5 / 0 0); // 此处 5 / 0 不会报错 System.out.println(result); } }如果没有短路运算后面的表达式会由于除数为0而报错但实际上该语句并未报错原因在于与运算是短路运算符提前计算出了结果false。如果变量b的值为true则表达式变为true (5 / 0 0)。因为无法进行短路运算该表达式必定会由于除数为0而报错可以自行测试。类似的对于||运算只要能确定第一个值为true后续计算也不再进行而是直接返回trueboolean result true || (5 / 0 0); // true三元运算符就是c语言中的三目运算符Java还提供一个三元运算符b ? x : y它根据第一个布尔表达式的结果分别返回后续两个表达式之一的计算结果。示例// 三元运算 public class Main { public static void main(String[] args) { int n -100; int x n 0 ? n : -n; System.out.println(x); } }上述语句的意思是判断n 0是否成立如果为true则返回n否则返回-n。这实际上是一个求绝对值的表达式。注意到三元运算b ? x : y会首先计算b如果b为true则只计算x否则只计算y。此外x和y的类型必须相同因为返回值不是boolean而是x和y之一。字符和字符串在Java中字符和字符串是两个不同的类型。字符类型字符类型char是基本数据类型它是character的缩写。一个char保存一个Unicode字符char c1 A; char c2 中;因为java在内存中总是使用Unicode表示字符所以一个英文字符和一个中文字符都用一个char类型表示它们都占用两个字节。要显示一个字符的Unicode编码只需将char类型直接赋值给int类型即可int n1 A; // 字母“A”的Unicodde编码是65 int n2 中; // 汉字“中”的Unicode编码是20013还可以直接用转义字符\uUnicode编码来表示一个字符// 注意是十六进制: char c3 \u0041; // A因为十六进制0041 十进制65 char c4 \u4e2d; // 中因为十六进制4e2d 十进制20013字符串类型和char类型不同字符串类型String是引用类型我们用双引号...表示字符串。一个字符串可以存储0个到任意个字符String s ; // 空字符串包含0个字符 String s1 A; // 包含一个字符 String s2 ABC; // 包含3个字符 String s3 中文 ABC; // 包含6个字符其中有一个空格因为字符串使用双引号...表示开始和结束那如果字符串本身恰好包含一个字符怎么表示例如abcxyz编译器就无法判断中间的引号究竟是字符串的一部分还是表示字符串结束。这个时候我们需要借助转义字符\String s abc\xyz; // 包含7个字符: a, b, c, , x, y, z因为\是转义字符所以两个\\表示一个\字符String s abc\\xyz; // 包含7个字符: a, b, c, \, x, y, z常见的转义字符包括\表示字符\表示字符\\表示字符\\n表示换行符\r表示回车符\t表示Tab\u####表示一个Unicode编码的字符例如String s ABC\n\u4e2d\u6587; // 包含6个字符: A, B, C, 换行符, 中, 文字符串连接相当于c语言中的stract方便了很多也体现了java面向对象的特点Java的编译器对字符串做了特殊照顾可以使用连接任意字符串和其他数据类型这样极大地方便了字符串的处理。例如// 字符串连接 public class Main { public static void main(String[] args) { String s1 Hello; String s2 world; String s s1 s2 !; System.out.println(s); // Hello world! } }如果用连接字符串和其他数据类型会将其他数据类型先自动转型为字符串再连接// 字符串连接 public class Main { public static void main(String[] args) { int age 25; String s age is age; System.out.println(s); // age is 25 } }多行字符串如果我们要表示多行字符串使用号连接会非常不方便String s first line \n second line \n end;从Java 13开始字符串可以用...表示多行字符串Text Blocks了。举个例子// 多行字符串 public class Main { public static void main(String[] args) { String s SELECT * FROM users WHERE id 100 ORDER BY name DESC ; System.out.println(s); } }上述多行字符串实际上是5行在最后一个DESC后面还有一个\n。如果我们不想在字符串末尾加一个\n就需要这么写String s SELECT * FROM users WHERE id 100 ORDER BY name DESC;还需要注意到多行字符串前面共同的空格会被去掉即String s ...........SELECT * FROM ........... users ...........WHERE id 100 ...........ORDER BY name DESC ...........;用.标注的空格都会被去掉。如果多行字符串的排版不规则那么去掉的空格就会变成这样String s ......... SELECT * FROM ......... users .........WHERE id 100 ......... ORDER BY name DESC ......... ;即总是以最短的行首空格为基准。不可变特性有点像指针的感觉Java的字符串除了是一个引用类型外还有个重要特点就是字符串不可变。考察以下代码观察执行结果难道字符串s变了吗其实变的不是字符串而是变量s的“指向”。执行String s hello;时JVM虚拟机先创建字符串hello然后把字符串变量s指向它s │ ▼ ┌───┬───────────┬───┐ │ │ hello │ │ └───┴───────────┴───┘紧接着执行s world;时JVM虚拟机先创建字符串world然后把字符串变量s指向它s ──────────────┐ │ ▼ ┌───┬───────────┬───┬───────────┬───┐ │ │ hello │ │ world │ │ └───┴───────────┴───┴───────────┴───┘原来的字符串hello还在只是我们无法通过变量s访问它而已。因此字符串的不可变是指字符串内容不可变。至于变量可以一会指向字符串hello一会指向字符串world。理解了引用类型的“指向”后试解释下面的代码输出// 字符串不可变 public class Main { public static void main(String[] args) { String s hello; String t s; s world; System.out.println(t); // t是hello还是world? } }空值null引用类型的变量可以指向一个空值null它表示不存在即该变量不指向任何对象。例如String s1 null; // s1是null String s2 s1; // s2也是null String s3 ; // s3指向空字符串不是null注意要区分空值null和空字符串空字符串是一个有效的字符串对象它不等于null。数组类型如果我们有一组类型相同的变量例如5位同学的成绩可以这么写public class Main { public static void main(String[] args) { // 5位同学的成绩: int n1 68; int n2 79; int n3 91; int n4 85; int n5 62; } }但其实没有必要定义5个int变量。可以使用数组来表示“一组”int类型。代码如下// 数组 public class Main { public static void main(String[] args) { // 5位同学的成绩: int[] ns new int[5]; ns[0] 68; ns[1] 79; ns[2] 91; ns[3] 85; ns[4] 62; } }定义一个数组类型的变量使用数组类型“类型[]”例如int[]。和单个基本类型变量不同数组变量初始化必须使用new int[5]表示创建一个可容纳5个int元素的数组。Java的数组有几个特点数组所有元素初始化为默认值整型都是0浮点型是0.0布尔型是false数组一旦创建后大小就不可改变。要访问数组中的某一个元素需要使用索引。数组索引从0开始例如5个元素的数组索引范围是0~4。可以修改数组中的某一个元素使用赋值语句例如ns[1] 79;。很像指针其实在内存的角度来看就是指针所以用指针的思想就好理解了可以用数组变量.length获取数组大小相当于strlen)// 数组 public class Main { public static void main(String[] args) { // 5位同学的成绩: int[] ns new int[5]; System.out.println(ns.length); // 5 } }也可以在定义数组时直接指定初始化的元素这样就不必写出数组大小而是由编译器自动推算数组大小。例如// 数组 public class Main { public static void main(String[] args) { // 5位同学的成绩: int[] ns new int[] { 68, 79, 91, 85, 62 }; System.out.println(ns.length); // 编译器自动推算数组大小为5 } }还可以进一步简写为int[] ns { 68, 79, 91, 85, 62 };注意数组是引用类型并且数组大小不可变。我们观察下面的代码// 数组 public class Main { public static void main(String[] args) { // 5位同学的成绩: int[] ns; ns new int[] { 68, 79, 91, 85, 62 }; System.out.println(ns.length); // 5 ns new int[] { 1, 2, 3 }; System.out.println(ns.length); // 3 } }数组大小变了吗看上去好像是变了但其实根本没变。对于数组ns来说执行ns new int[] { 68, 79, 91, 85, 62 };时它指向一个5个元素的数组ns │ ▼ ┌───┬───┬───┬───┬───┬───┬───┐ │ │68 │79 │91 │85 │62 │ │ └───┴───┴───┴───┴───┴───┴───┘执行ns new int[] { 1, 2, 3 };时它指向一个新的3个元素的数组ns ──────────────────────┐ │ ▼ ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐ │ │68 │79 │91 │85 │62 │ │ 1 │ 2 │ 3 │ │ └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘但是原有的5个元素的数组并没有改变只是无法通过变量ns引用到它们而已。字符串数组如果数组元素不是基本类型而是一个引用类型那么修改数组元素会有哪些不同字符串是引用类型因此我们先定义一个字符串数组String[] names { ABC, XYZ, zoo };对于String[]类型的数组变量names它实际上包含3个元素但每个元素都指向某个字符串对象┌─────────────────────────┐ names │ ┌─────────────────────┼───────────┐ │ │ │ │ │ ▼ │ │ ▼ ▼ ┌───┬───┬─┴─┬─┴─┬───┬───────┬───┬───────┬───┬───────┬───┐ │ │░░░│░░░│░░░│ │ ABC │ │ XYZ │ │ zoo │ │ └───┴─┬─┴───┴───┴───┴───────┴───┴───────┴───┴───────┴───┘ │ ▲ └─────────────────┘对names[1]进行赋值例如names[1] cat;效果如下┌─────────────────────────────────────────────────┐ names │ ┌─────────────────────────────────┐ │ │ │ │ │ │ ▼ │ │ ▼ ▼ ┌───┬───┬─┴─┬─┴─┬───┬───────┬───┬───────┬───┬───────┬───┬───────┬───┐ │ │░░░│░░░│░░░│ │ ABC │ │ XYZ │ │ zoo │ │ cat │ │ └───┴─┬─┴───┴───┴───┴───────┴───┴───────┴───┴───────┴───┴───────┴───┘ │ ▲ └─────────────────┘这里注意到原来names[1]指向的字符串XYZ并没有改变仅仅是将names[1]的引用从指向XYZ改成了指向cat其结果是字符串XYZ再也无法通过names[1]访问到了。对“指向”有了更深入的理解后试解释如下代码// 数组 public class Main { public static void main(String[] args) { String[] names {ABC, XYZ, zoo}; String s names[1]; names[1] cat; System.out.println(s); // s是XYZ还是cat? } }输入输出输出在前面的代码中我们总是使用System.out.println()来向屏幕输出一些内容。println是print line的缩写表示输出并换行(printf(\n))。因此如果输出后不想换行可以用print()// 输出 public class Main { public static void main(String[] args) { System.out.print(A,); System.out.print(B,); System.out.print(C.); System.out.println(); System.out.println(END); } }注意观察上述代码的执行效果。格式化输出Java还提供了格式化输出的功能。为什么要格式化输出因为计算机表示的数据不一定适合人来阅读// 格式化输出 public class Main { public static void main(String[] args) { double d 12900000; System.out.println(d); // 1.29E7 } }如果要把数据显示成我们期望的格式就需要使用格式化输出的功能。格式化输出使用System.out.printf()通过使用占位符%?printf()可以把后面的参数格式化成指定格式// 格式化输出 public class Main { public static void main(String[] args) { double d 3.1415926; System.out.printf(%.2f\n, d); // 显示两位小数3.14 System.out.printf(%.4f\n, d); // 显示4位小数3.1416 } }Java的格式化功能提供了多种占位符可以把各种数据类型“格式化”成指定的字符串占位符说明%d格式化输出整数%x格式化输出十六进制整数%f格式化输出浮点数%e格式化输出科学计数法表示的浮点数%s格式化字符串注意由于%表示占位符因此连续两个%%表示一个%字符本身。占位符本身还可以有更详细的格式化参数。下面的例子把一个整数格式化成十六进制并用0补足8位// 格式化输出 public class Main { public static void main(String[] args) { int n 12345000; System.out.printf(n%d, hex%08x, n, n); // 注意两个%占位符必须传入两个数 } }详细的格式化参数请参考JDK文档java.util.Formatter输入和输出相比Java的输入就要复杂得多。我们先看一个从控制台读取一个字符串和一个整数的例子import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner new Scanner(System.in); // 创建Scanner对象 System.out.print(Input your name: ); // 打印提示 String name scanner.nextLine(); // 读取一行输入并获取字符串 System.out.print(Input your age: ); // 打印提示 int age scanner.nextInt(); // 读取一行输入并获取整数 System.out.printf(Hi, %s, you are %d\n, name, age); // 格式化输出 } }首先我们通过import语句导入java.util.Scannerimport是导入某个类的语句必须放到Java源代码的开头后面我们在Java的package中会详细讲解如何使用import。然后创建Scanner对象并传入System.in。System.out代表标准输出流而System.in代表标准输入流。直接使用System.in读取用户输入虽然是可以的但需要更复杂的代码而通过Scanner就可以简化后续的代码。有了Scanner对象后要读取用户输入的字符串使用scanner.nextLine()要读取用户输入的整数使用scanner.nextInt()。Scanner会自动转换数据类型因此不必手动转换。要测试输入必须从命令行读取用户输入因此需要走编译、执行的流程$ javac Main.java这个程序编译时如果有警告可以暂时忽略它在后面学习IO的时候再详细解释。编译成功后执行$ java Main Input your name: Bob ◀── 输入 Bob Input your age: 12 ◀── 输入 12 Hi, Bob, you are 12 ◀── 输出根据提示分别输入一个字符串和整数后我们得到了格式化的输出。三最后一语今天真是爆更了一万四千字之前有这个零头就不错了。主要是想快点进入数据结构与算法真题的节奏所以这次量大管饱的更新大家要好好吸收。对每个人而言真正的职责只有一个找到自我。然后在心中坚守其一生全心全意永不停息。---赫尔曼.黑塞《德米安彷徨少年时》感谢观看共勉