CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛

java学习笔记(一)——java简介-免费源码丞旭猿

为什么Java应用最广泛?

从互联网到企业平台,Java是应用最广泛的编程语言,原因在于:

  • Java是基于JVM虚拟机的跨平台语言,一次编写,到处运行;
  • Java程序易于编写,而且有内置垃圾收集,不必考虑内存管理;
  • Java虚拟机拥有工业级的稳定性和高度优化的性能,且经过了长时期的考验;
  • Java拥有最广泛的开源社区支持,各种高质量组件随时可用。

Java语言常年霸占着三大市场:

  • 互联网和企业应用,这是Java EE的长期优势和市场地位;
  • 大数据平台,主要有Hadoop、Spark、Flink等,他们都是Java或Scala(一种运行于JVM的编程语言)开发的;
  • Android移动平台。

这意味着Java拥有最广泛的就业市场。

Java最早是由SUN公司(已被Oracle收购)的詹姆斯·高斯林(高司令,人称Java之父)在上个世纪90年代初开发的一种编程语言,最初被命名为Oak,随着互联网的崛起Oak重新焕发生机。在1995年以Java的名称正式发布,原因是Oak已经被人注册了,因此SUN注册了Java这个商标。

Java介于编译型语言和解释型语言之间。Java是将代码编译成一种字节码,它类似于抽象的CPU指令,然后,针对不同平台编写虚拟机,不同平台的虚拟机负责加载字节码并执行,这样就实现了一次编写,到处运行的效果。当然,这是针对Java开发者而言。对于虚拟机,需要为每个平台分别开发。为了保证不同平台、不同公司开发的虚拟机都能正确执行Java字节码,SUN公司制定了一系列的Java虚拟机规范。从实践的角度看,JVM的兼容性做得非常好,低版本的Java字节码完全可以正常运行在高版本的JVM上。

随着Java的发展,SUN给Java又分出了三个不同版本:

  • Java SE:Standard Edition
  • Java EE:Enterprise Edition
  • Java ME:Micro Edition
  • 这三者的关系如下图所示:

简单来说,Java SE就是标准版,包含标准的JVM和标准库,而Java EE是企业版,它只是在Java SE的基础上加上了大量的API和库,以便方便开发Web应用、数据库、消息服务等,Java EE的应用使用的虚拟机和Java SE完全相同。

Java ME就和Java SE不同,它是一个针对嵌入式设备的瘦身版,Java SE的标准库无法在Java ME上使用,Java ME的虚拟机也是瘦身版。

因此我们推荐的Java学习路线图如下:

  1. 首先要学习Java SE,掌握Java语言本身、Java核心开发技术以及Java标准库的使用;
  2. 如果继续学习Java EE,那么Spring框架、数据库开发、分布式架构就是需要学习的;
  3. 如果要学习大数据开发,那么Hadoop、Spark、Flink这些大数据平台就是需要学习的,他们都基于Java或Scala开发;
  4. 如果想要学习移动开发,那么就深入Android平台,掌握Android App开发。

无论怎么选择,Java SE的核心技术是基础,这个教程的目的就是让你完全精通Java SE!

从1995年发布1.0版本开始,到目前为止,最新的Java版本是Java 15:

名词解释

初学者学Java,经常听到JDK、JRE这些名词,它们到底是啥?

  • JDK:Java Development Kit
  • JRE:Java Runtime Environment

简单地说,JRE就是运行Java字节码的虚拟机。但是,如果只有Java源码,要编译成Java字节码,就需要JDK,因为JDK除了包含JRE,还提供了编译器、调试器等开发工具。

二者关系如下:

  • JSR规范:Java Specification Request
  • JCP组织:Java Community Process

变量和数据类型

我们先讨论基本类型的变量。Java提供了两种变量类型:基本类型和引用类型

在Java中,变量必须先定义后使用,在定义变量的时候,可以给它一个初始值。例如:

intx = 1;

我们一行一行地分析代码执行流程:

执行int n = 100;,该语句定义了变量n,同时赋值为100,因此,JVM在内存中为变量n分配一个存储单元,填入值100

执行n = 200;时,JVM把200写入变量n的存储单元,因此,原有的值被覆盖,现在n的值为200

执行int x = n;时,定义了一个新的变量x,同时对x赋值,因此,JVM需要新分配一个存储单元给变量x,并写入和变量n一样的值,结果是变量x的值也变为200

执行x = x + 100;时,JVM首先计算等式右边的值x + 100,结果为300(因为此刻x的值为200),然后,将结果300写入x的存储单元,因此,变量x最终的值变为300

可见,变量可以反复赋值。注意,等号=是赋值语句,不是数学意义上的相等,否则无法解释x = x + 100

基本数据类型

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

计算机内存的最小存储单元是字节(byte),一个字节就是一个8位二进制数,即8个bit。它的二进制表示范围从00000000~11111111,换算成十进制是0~255,换算成十六进制是00~ff

内存单元从0开始编号,称为内存地址。每个内存单元可以看作一间房间,内存地址就是门牌号。

一个字节是1byte,1024字节是1K,1024K是1M,1024M是1G,1024G是1T。

不同的数据类型占用的字节数不一样。我们看一下Java基本数据类型占用的字节数:

byte恰好就是一个字节,而longdouble需要8个字节。

也可以将结果强制转型,即将大范围的整数转型为小范围的整数。强制转型使用(类型),例如,将int强制转型为short

inti = 12345;shorts = (short) i;// 12345

浮点数常常无法精确表示,并且浮点数的运算结果可能有误差;

比较两个浮点数通常比较它们的绝对值之差是否小于一个特定值;

整型和浮点型运算时,整型会自动提升为浮点型;

可以将浮点型强制转为整型,但超出范围后将始终返回整型的最大值。

Java的编译器对字符串做了特殊照顾,可以使用+连接任意字符串和其他数据类型,这样极大地方便了字符串的处理。

Java的字符类型char是基本类型,字符串类型String是引用类型;

基本类型的变量是持有某个数值,引用类型的变量是指向某个对象;

引用类型的变量可以是空值null

要区分空值null和空字符串""

流程控制

输出:

在前面的代码中,我们总是使用System.out.println()来向屏幕输出一些内容。

println是print line的缩写,表示输出并换行。因此,如果输出后不想换行,可以用print()

浮点数的比较不能用等号,因为有精度问题:

publicclassMain{publicstaticvoidmain(String[]args){doublex=1-9.0/10;if(Math.abs(x-0.1)<0.00001){System.out.println("x is 0.1");}else{System.out.println("x is NOT 0.1");}}}

判断引用类型相等

在Java中,判断值类型的变量是否相等,可以使用==运算符。但是,判断引用类型的变量是否相等,==表示引用是否相等,或者说,是否指向同一个对象。例如,下面的两个String类型,它们的内容是相同的,但是,分别指向不同的对象,用==判断,结果为false

要判断引用类型的变量内容是否相等,必须使用equals()方法

switch表达式

使用switch时,如果遗漏了break,就会造成严重的逻辑错误,而且不易在源代码中发现错误。从Java 12开始,switch语句升级为更简洁的表达式语法,使用类似模式匹配(Pattern Matching)的方法,保证只有一种路径会被执行,并且不需要break语句:

publicclassMain{publicstaticvoidmain(String[]args){Stringfruit="apple";switch(fruit){case"apple"->System.out.println("Selected apple");case"pear"->System.out.println("Selected pear");case"mango"->{System.out.println("Selected mango");System.out.println("Good choice!");}default->System.out.println("No fruit selected");}}}

yield

大多数时候,在switch表达式内部,我们会返回简单的值。

但是,如果需要复杂的语句,我们也可以写很多语句,放到{...}里,然后,用yield返回一个值作为switch语句的返回值:

publicclassMain{publicstaticvoidmain(String[]args){Stringfruit="orange";intopt=switch(fruit){case"apple"->1;case"pear","mango"->2;default->{intcode=fruit.hashCode();yieldcode;// switch语句返回值}};System.out.println("opt = "+opt);}}

表面上看,上面的while循环是一个死循环,但是,Java的int类型有最大值,达到最大值后,再加1会变成负数,结果,意外退出了while循环。

但是,很多时候,我们实际上真正想要访问的是数组每个元素的值。Java还提供了另一种for each循环,它可以更简单地遍历数组:

publicclassMain{publicstaticvoidmain(String[]args){int[]ns={1,4,9,16,25};for(intn:ns){System.out.println(n);}}}

遍历数组for

publicclassMain{publicstaticvoidmain(String[]args){int[]ns={1,4,9,16,25};for(inti=0;i<ns.length;i++){intn=ns[i];System.out.println(n);}}}

遍历数组foreach

publicclassMain{publicstaticvoidmain(String[]args){int[]ns={1,4,9,16,25};for(intn:ns){System.out.println(n);}}}

注意:在for (int n : ns)循环中,变量n直接拿到ns数组的元素,而不是索引。

显然for each循环更加简洁。但是,foreach循环无法拿到数组的索引,因此,到底用哪一种for循环,取决于我们的需要。

数组排序

冒泡排序

import java.util.Arrays;

publicclassMain{publicstaticvoidmain(String[]args){int[]ns={28,12,89,73,65,18,96,50,8,36};// 排序前:System.out.println(Arrays.toString(ns));for(inti=0;i<ns.length-1;i++){for(intj=0;j<ns.length-i-1;j++){if(ns[j]>ns[j+1]){// 交换ns[j]和ns[j+1]:inttmp=ns[j];ns[j]=ns[j+1];ns[j+1]=tmp;}}}// 排序后:System.out.println(Arrays.toString(ns));}}冒泡排序的特点是每一轮循环后最大的一个数被交换到末尾因此下一轮循环就可以刨除最后的数每一轮循环都比上一轮循环的结束位置靠前一位另外注意到交换两个变量的值必须借助一个临时变量像这么写是错误的

二维数组

importjava.util.Arrays;publicclassMain{publicstaticvoidmain(String[]args){int[][]ns={{1,2,3,4},{5,6,7,8},{9,10,11,12}};System.out.println(Arrays.deepToString(ns));}}

三维数组

int[][][]ns={{{1,2,3},{4,5,6},{7,8,9}},{{10,11},{12,13}},{{14,15,16},{17,18}}};

二维数组就是数组的数组,三维数组就是二维数组的数组;

多维数组的每个数组元素长度都不要求相同;

打印多维数组可以使用Arrays.deepToString()

最常见的多维数组是二维数组,访问二维数组的一个元素使用array[row][col]

面向对象编程

定义class

在Java中,创建一个类,例如,给这个类命名为Person,就是定义一个class

classPerson{publicStringname;publicintage;}

一个class可以包含多个字段(field),字段用来描述一个类的特征。上面的Person类,我们定义了两个字段,一个是String类型的字段,命名为name,一个是int类型的字段,命名为age。因此,通过class,把一组数据汇集到一个对象上,实现了数据封装。

public是用来修饰字段的,它表示这个字段可以被外部访问。

创建实例

Personming=newPerson();

上述代码创建了一个Person类型的实例,并通过变量ming指向它。

注意区分Person ming是定义Person类型的变量ming,而new Person()是创建Person实例。

有了指向这个实例的变量,我们就可以通过这个变量来操作实例。访问实例变量可以用变量.字段,例如:

ming.name="Xiao Ming";// 对字段name赋值ming.age=12;// 对字段age赋值System.out.println(ming.name);// 访问字段namePersonhong=newPerson();hong.name="Xiao Hong";hong.age=15;

fieldpublic改成private,外部代码不能访问这些field,那我们定义这些field有什么用?怎么才能给它赋值?怎么才能读取它的值?

所以我们需要使用方法(method)来让外部代码可以间接修改field

publicclassMain{publicstaticvoidmain(String[]args){Personming=newPerson();ming.setName("Xiao Ming");// 设置nameming.setAge(12);// 设置ageSystem.out.println(ming.getName()+", "+ming.getAge());}}
classPerson{privateStringname;privateintage;publicStringgetName(){returnthis.name;}publicvoidsetName(Stringname){this.name=name;}publicintgetAge(){returnthis.age;}publicvoidsetAge(intage){if(age<0||age>100){thrownewIllegalArgumentException("invalid age value");}this.age=age;}}

虽然外部代码不能直接修改private字段,但是,外部代码可以调用方法setName()setAge()来间接修改private字段。在方法内部,我们就有机会检查参数对不对。比如,setAge()就会检查传入的参数,参数超出了范围,直接报错。这样,外部代码就没有任何机会把age设置成不合理的值。

setName()方法同样可以做检查,例如,不允许传入null和空字符串:

publicvoidsetName(Stringname){if(name==null||name.isBlank()){thrownewIllegalArgumentException("invalid name");}this.name=name.strip();// 去掉首尾空格}

构造方法

创建实例的时候,实际上是通过构造方法来初始化实例的。我们先来定义一个构造方法,能在创建Person实例的时候,一次性传入nameage,完成初始化:

publicclassMain{publicstaticvoidmain(String[]args){Personp=newPerson("Xiao Ming",15);System.out.println(p.getName());System.out.println(p.getAge());}}classPerson{privateStringname;privateintage;publicPerson(Stringname,intage){this.name=name;this.age=age;}publicStringgetName(){returnthis.name;}publicintgetAge(){returnthis.age;}}

由于构造方法是如此特殊,所以构造方法的名称就是类名。构造方法的参数没有限制,在方法内部,也可以编写任意语句。但是,和普通方法相比,构造方法没有返回值(也没有void),调用构造方法,必须用new操作符。

如果既要能使用带参数的构造方法,又想保留不带参数的构造方法,那么只能把两个构造方法都定义出来:

// 构造方法

publicclassMain{publicstaticvoidmain(String[]args){Personp1=newPerson("Xiao Ming",15);// 既可以调用带参数的构造方法Personp2=newPerson();// 也可以调用无参数构造方法}}classPerson{privateStringname;privateintage;publicPerson(){}publicPerson(Stringname,intage){this.name=name;this.age=age;}publicStringgetName(){returnthis.name;}publicintgetAge(){returnthis.age;}}

没有在构造方法中初始化字段时,引用类型的字段默认是null,数值类型的字段用默认值,int类型默认值是0,布尔类型默认值是false

方法重载

在一个类中,我们可以定义多个方法。如果有一系列方法,它们的功能都是类似的,只有参数有所不同,那么,可以把这一组方法名做成同名方法。例如,在Hello类中,定义多个hello()方法:

classHello{publicvoidhello(){System.out.println("Hello, world!");}publicvoidhello(Stringname){System.out.println("Hello, "+name+"!");}publicvoidhello(Stringname,intage){if(age<18){System.out.println("Hi, "+name+"!");}else{System.out.println("Hello, "+name+"!");}}}

这种方法名相同,但各自的参数不同,称为方法重载(Overload)。重载方法返回值类型应该相同。

继承

//person类classPerson{privateStringname;privateintage;publicStringgetName(){...}publicvoidsetName(Stringname){...}publicintgetAge(){...}publicvoidsetAge(intage){...}}

现在,假设需要定义一个Student类,字段如下:

classStudent{privateStringname;privateintage;privateintscore;publicStringgetName(){...}publicvoidsetName(Stringname){...}publicintgetAge(){...}publicvoidsetAge(intage){...}publicintgetScore(){}publicvoidsetScore(intscore){}}

继承是面向对象编程中非常强大的一种机制,它首先可以复用代码。当我们让StudentPerson继承时,Student就获得了Person的所有功能,我们只需要为Student编写新增的功能。

注意:子类自动获得了父类的所有字段,严禁定义与父类重名的字段!

Java只允许一个class继承自一个类,因此,一个类有且仅有一个父类。只有Object特殊,它没有父类。

protected

继承有个特点,就是子类无法访问父类的private字段或者private方法。例如,Student类就无法访问Person类的nameage字段:

这使得继承的作用被削弱了。为了让子类可以访问父类的字段,我们需要把private改为protected。用protected修饰的字段可以被子类访问:

声明:本文部分素材转载自互联网,如有侵权立即删除 。

© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
相关推荐
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容