目录
1.JAVA基础知识点简介
1.1.java的JDK安装教程
2.JAVA的变量
3.什么是面向对象 ,如何学习
4.创建类的方法 ,类的表示方法
5.1.类和对象的关系
5.2.函数的重载
5.3构造函数
6.this关键词的用法
7.static 关键字的用法
8.继承
8.1.使用super调用父类构造函数的方法
8.2函数的复写
9.JAVA的对象转型
9.1向上转型
11.抽象类和抽象函数
11.1为什么要使用抽象类
12.包和访问权限
12.1给一个类打包
12.2JAVA当中访问权限
12.3如何导入一个包
12.4包的访问权限和继承
13.Java 的接口(重点)
14.JAVA当中的异常机制
15.JAVA的IO系统
16.内部类和匿名内部类
17.JAVA 当中的线程
18.JAVA数组
19.JAVA的类集框架
20.equals函数
21.hashCode 和 toString方法
22.Java开发工具(Eclipse)
1.什么是环境变量:通常是指在操作系统当中,用来指定操作系统运行时所需要的参数。
2.Path环境变量:是操作系统外部命令搜索路径。
3.window+R,输入cmd 输入 ipconfig ,按下命令,显示计算机网卡配置
为什么会有这个结果?
其实是操作系统执行ipconfig.exe的可执行文件。
4.操作系统在哪里找这个ipconfig.exe 这个文件在电脑路径:C:\Windows\System32 中有ipconfig.exe的文件。如果改变ipconfig 的名字为iconfig ,再次在cmd里面输入ipconfig命令,提示不是内部或外部命令,也不是可运行的程序。
例如:系统环境变量
5.在路径 :C:\Program Files\Java\jdk1.8.0_05\bin 中有java.exe 这个文件,如何找到这个文件也是通过系统Path路径。
6.classpath环境变量:类文件搜索路径 "."代表是当前目录 执行 Hello.class这个文件需要去哪里找这个文件? "." 代表在当前目录去寻找。
7.总结:Path 用来寻找命令的路径,classpath用来寻找类文件的路径(以 .class为结尾的文件就是类文件。)
8.JDK 里面有什么东西?
9.JVM是Java Virtual Machine(Java虚拟机)的缩写,他是由一个软件虚拟出来的计算机,不是实际的计算机。
流程:1.程序员写程序,编译器检测是否通过,不通过返回。
(编译器把程序翻译成虚拟机可以理解的代码)
2.编译成计算机识别的二进制代码(.class files)。
3.在不同平台运行,是虚拟机需要完成的东西。
4.虚拟机把(.class)文件翻译成操作系统可以理解的代码。
首先在官网下载jdk安装包
官网链接:点我下载
答:要将信息存储在计算机当中,就必须指明信息存储的位置和所需的内存空间。
类型 |
占用存储空间 |
表数范围 |
byte |
1字节 |
-128~127 |
short |
2字节 |
-2的15次方~2的15次方-1 |
int |
4字节 |
-2的31次方~2的31次方-1 |
long |
8字节 |
-2的63次方~2的63次方-1 |
浮点类型 |
|
|
float |
4字节 |
|
double |
8字节 |
|
十进制整数,如12,-314,0。1).Java语言整型常量的三种表示形式:
八进制整数,要求以0开头,如012。
十六进制数,要求0x或0X开头,如0x12。
2).Java语言的整型常亮默认为int 型,如 :int i=3;
3).声明long型常亮可以后加'l'或者'L',如 long l=3L;
12.变量命名规范:
1.变量命名语法规范:
1).应该以字母、下划线或者美元符开头。
2).后面跟字母、下划线、美元符或者是数字。
3).Java变量名没有长度的限制。
4).Java变量名对大小写敏感。
2.驼峰命名法:
1).变量名应该是有意义的英文单词。
2).变量名如果只有一个单词,则所有字母小写。
3).变量名如果由多个英文单词组成,则从第二个单词开始首字母大写。
13.Java字符使用Unicode字符集:
ASCII全称为:American Standard Code for Information Interchange(美国标准信息交换码)
1.对字符集的理解可以从以下几方面入手:
1).在计算机当中,所有的数据都需要使用二进制数字表示
2).类似a、b、c之类的字母无法直接用二进制表示。
3).所以就将所有常见的符号进行编号。标准ASCII码使用7位二进制数来表示字符。
4).7位2进制可以表示所有的数字,大写字母以及一些常见的符号。 (例如:!,@,#,$等等)
2.Unicode 为每种语言的每个字符设定了统一并且唯一的二进制编码
1).Unicode满足了跨语言文本转换和处理的需求。
2).Unicode在互联网当中扮演着十分重要的角色。
3).Unicode使用数字0-0x10ffff来表示字符。
4).最多允许1114112个字符。
例子:打开文本编辑器:输入联通,保存,再次打开,出现乱码?
答: 当写入联通两个字的时候,是通过字符集,装换成数字,存放在硬盘如果用 a字符 集,转换联通存入一个二进制到硬盘,读取的时候,用 b字符集翻译回来,就会出错。
14.Java与Unicode字符集
答:由于Java在设计初期就考虑到将语言使用在互联网当中,所以设计者们就选用Unicode 字符集,这也使得Java程序 能够在互联网当中更好的流通,也正是由于这样的原因,以下代 码是合法的:char c = '中';
1).面向对象是一种编程方法。
2).面向对象是一种思维方式。
3).面向对象不是一种编程语言。
1).掌握一门面向对象语言的语法。
2).掌握面向对象的思维方式(现实方式的思维方式)。
2.1).首先确定谁来做,其次确定怎么做。
2.2).首先考虑整体,其次考虑局部。
2.3).首先考虑抽象,其次考虑具体。
3).熟悉面向对象设计原则(呈金字塔型,消除应用程序重复代码)。
4).掌握面向对象的设计模式(前人设计经验总结,解决问题的方法)。
class 类名(相当c语言的结构体)
{
属性; //属性也叫成员变量,主要用于描述类的状态
方法; //方法也叫成员方法,主要用于描述类的行为
}
class Person{ //Person为类名
int age; //age为成员变量
void shout() { //shout 为成员函数
System.out.println("oh,my god! I am" + age);
}
}
-age是类的属性,也叫类的成员变量。
-shout是方法也叫类的成员函数。
-shout方法可以直接访问同一个类中age变量,如果一个方法中
有与成员变量同名的局部变量,该方法中对这个变量名的访问
时局部变量,而不是成员变量。
例子:在c语言中定义一个结构体:
typedef struct st{
int age;
int high;
}Dog;
例子:在Java中创建一个名为 Dog 的类。
引用过程:创建一个新(引用)变量:Dog dog;
格式:类名 对象名=new 类名();
例如:Dog dog =new Dog(); //已经定义一个Dog的对象
Dog和int 是一个意思,是一个类型,而Dog是一个引用数据类型(跟c语言的结构体是一样的)。
1.Dog d //创建一个Dog的引用
2.new Dog(); //创建一个Dog对象
3.= //将创建的Dog对象赋值给引用‘d’
类是抽象的,一系列具有共同特征的事物,比如狗,有身高体重,而对象是具体的,比如具体是哪一条狗。
18.使用变量和函数:
1).对象的使用方法:
例子:在Dog.java 中创建一个类
在Text.java 中创建一个对象和调用对象
运行Text.java
进去命令运行窗口:
然后再进入你文件所在的位置:
1.两个或多个函数出现在同一个类当中。
2.函数名相同。
3.参数列表不同。
例子:在A.java 中建立一个类:
在Text.java 中
输出结果:
通俗例子:生活中有 “洗”这个概念,洗衣服也是洗,洗脸也是洗,不能用同样的方法去洗,洗是一个抽象的概念,洗什么是具体的事件。
在Text.java 中
运行结果:
构造函数的例子:
在Text.java 中
运行结果:
注意:如果一个类没有建立构造函数,这个类在运行的时候就会自动为这个类添加一个参数为空何函数体为空的构造函数,如果一个类中已经有构造函数,编译器不会自动添加参数为空的构造函数(调用无参数的构造函数就会出错)。
1).例子:创建一个Person.java 的文件
1.静态成员变量只有一份。
2.在静态函数当中不能使用this.
3.静态代码块的主要作用是为静态成员变量赋值。
如何定义:在变量前面加一个 static int i;
Person p1 = new Person();
P1.i=10;
Person p2 = new Person();
P2.i=20;
注意:所有的静态变量使用的是同一个,无论是p1修改还是p2修改这个i成员变量的值,这个值就会同时变化;
继承(三大特征:继承,封装,多态),为了减少应用程序的重复代码
在现实生活中,继承就是儿子得到了老子的东西。
在面向对象的世界当中,继承就是一个类得到了另一类当中的成员变量和成员函数的方法。
注意:Java只支持单继承,不允许多继承。
例子1:
//Person 为父类,Student 为子类,extends为继承的关系
证实:
执行步骤:1.编译javac Person 2.编译 javac Student 3.编译 javac Text 4.执行java Text
--除了继承还可以增加新的东西?
然后修改 Text.java
输出结果:
注意:子类能继承父类的成员变量和函数,却不能继承父类的构造函数,在成员变量赋值的时候可能出现重复代码,可以通过调 用 super();来调用父类的构造函数
例子1:1).建立Person.java的文件,加上构造函数
2).定义一个Student 的类,继承Person,但是构造函数不能被继承;
3).建立一个Text.java 的函数入口
输出结果:
如果在子类Student.java当中代码是这样
在Text.java 文件中,创建一个新的对象 student
运行结果:
例子 :
2).再创建一个子类 Student ,继承父类 Person 的name ,age ,introduce();
3).创建一个类,调用Student 函数
运行结果:
向上转型—将子类的对象赋值给父类引用。(一定可以成功)
前提:Student 是 Person 的子类。
例如:s 代表张三这个学生对象。说张三是个Person对象也是没毛病。
例子:
2).再创建一个子类 Student,继承父类Person
3).创建一个类,调用Student 函数
注意:1.一个引用能调用那些成员(变量和函数),取决于这个引用类型。
2.一个引用调用的是哪一个方法,取决于这个引用所指的对象。
输出结果:
//首先向上转型
Student s1 = new Student();
Person p = s1;
Student s2 = (Student)p; //强制类型转换
class Text{
public static void main(String args[]){
Student s1 = new Student(); //生成一个新的 Student 的对象p
Person p = s1; //首先向上继承
Student s2 = (Student)p; //再向下继承
}
}
模拟需需求场景,应用前面所学知识。
1).客户的第一要求:开发一个打印机控制程序,能够实现开机、关机、和打印功能。
2).客户二次需求:我的办公室加了一台新的打印机,把你的程序修改一下,应该很 简单吧(不是同一个型号)。
1.修改打印机的类名为 HPPrinter.然后再增加一个类 CanonPriner
2.测试程序:
--虽然程序开发完成了,但是存在很多重复代码??????????
如果类越多,重复代码就越多。
解决方案: 惠普打印机和佳能打印机都是打印机,则创建一个类为打印机这个类,则打印机为父类,佳能和惠普继承这个父 类。
2.创建惠普 HPPrinter 这个类 继承父类 Print
3.创建佳能 CannonPriner 这个类,继承父类Print
重复代码全部消除,如果再次添加一个打印机就会容易很多,我们只需要新建一个类去继承Printer这个类,然后根据功能复写父类
1.抽象函数就是没有函数体的函数。
2.抽象函数使用abstract 来定义
3.抽象类不能生成对象,但是却可以拥有构造函数。
函数的定义:有返回值类型,函数名,参数列表
函数体 :大括号,和大括号中间的内容
什么是抽象函数?
答:只有函数的定义,没有函数体的函数,被称为抽象函数。
abstract void fun();
什么是抽象类?
使用abstract 定义的类被称为抽象类。
抽象类不能生成对象。
如果一个类中包含有抽象函数,那么这个类必须被声明为抽象类。
如果一个类当中没有抽象函数,那么这个类也可以被声明为抽象类。(不能被生成对象,被称为基类,只能被继承)
反推:如果能生成抽象类对象的话,就能调用抽象类函数,如果 这样的话,抽象类函数没有函数体,就会出错(所以抽象类不能生成对象)!
答:抽象类天生就是用来当爹的,只能用于继承。
新建一个类 Chinese 继承Person
新建一个类 Text
输出结果:
条件:
抽象类不能生成对象。
构造函数用于生成类的对象。
可以有构造函数:但是为子类集成的时候用的,可以通过super(); 继承抽象类函数的构造函数。
证明:
例子:新建一个类Person(抽象类不能生成对象)
新建一个类 Chinese 继承Person
新建一个类 Text
输出结果:
结论:Person 这个类,虽然不能直接调用他的抽象函数的构造函数,但是抽象类的子类却可以通过super(); 调用父类的构造函数。
注意:如果 把一个类定义为抽象类,里面有一个抽象函数。如果需要继承这个父类,必须去复写这个函数,才能编译通过。
1.软件包为Java类提供了命名的空间(两个类可以同名,但不同空间(文件夹))。
2.打包时需要使用package指令。
3.一个类的全名应该是“包名”+“类名”。
有两个软对分别开发,学生管理系统,和注册用户管理系统
团队A 团队B
——在分开测试的时候没有任何问题。但一旦合并使用就会出现重名的问题 。
解决方法:
1.可以使用不同的User 比如 Auser 和 Buser
2.使用软件包
//将类放置到一个包当中,需要使用package+包名
//编译时需要使用 –d,该参数的作用是依照包生成相应的文件夹
//一个类的全名应该是”包名” + ”.” + “类名” yuan.Text 。
//即使进入到 yuan 文件夹,然后执行Text 也不行。
注意:即使进入yuan文件夹执行java Text 出错。只能运行整个类
1.要求包名所有的字母都要小写
2.包名一般情况下,是你的域名倒过来写
1.public可以修饰成员变量和成员函数,没有任何限制,在不在同个包都可以 访问。
2.private 可以修饰成员变量和成员函数,只能在本类当中使用
3.default(不写权限修饰符,就是default 权限)可以修饰类、成员变量和成员函数,在同一个包可以自由访问,不同不可以。
1).例子:
新建一个类Person.java
新建一个Text.java 的类。
编译:
此时编译没有问题,但是当去掉 Person 类的public 声明去掉。
再次编译:
出错,解释,如果一个类不是公共,那么在Text 类中就没有办法使用同一个类(前提:两个类不在同一个包中)。
2).例子:
新建一个类Person.java
新建一个Text.java 的类。
结论:(两个类在不同的包)一个类向访问另一类,被访问的类必须有public 权限,被访问的成员变量也必须有public权限。
例子:新建一个类Person.java
新建一个Text.java 的类。
出错:结论:无论在不在同一个包里,如果声明为private ,只能在本类使用成员变量或者是成员函数。
新建一个类Person.java
例子:新建一个Text.java 的类。Person 的包在org.yuan 中
1.如果父类和子类不在同一个包中,子类可以继承default 权限成员变量和成员函数,但是由于权限不够,无法使用。
2.如果希望一个包的变量和成员函数,被跨包继承的话,就需要给被继承的变量public权限。
1).新建一个类Person,给Person 打个包
2).新建一个Student 继承Person,给Student 打个包
1.protected 权限首先拥有和default 一样的功能,但是该权限只能修饰成员变量和成员函数。
1).什么是接口?
接口就是标准
2).接口的基本语法(一)
1.使用interface 定义
2.接口当中的方法是抽象方法(默认为 abstract(抽象方法),用来继承)。(用一个类用来继承接口,然后复写抽象函数)
3.接口当中的所有权限都是public权限
例子:(implements(实现)是特殊的继承)
2).接口的基本语法(二)
1.实现接口使用 implements 关键字。
2.一个类可以实现多个接口(手机可以用usb和WiFi功能)。(每个标准是一个接口)
3.一个接口可以继承多个接口。
例子:手机能用usb 跟电脑通信,又能用WiFi和电脑通信,所以这手机既支持usb接口,又支持WiFi接口。所以一个类可以实现(ipmlememts)多个接口.
实例 :建立一个接口称为 USB
再建立一个WIFI接口:
用 Phone 这个类去实现 USB和WiFi 接口
建立一个类Text 作为程序入口
例子:打印机,新建一个打印机(Printer)的接口,然后让(HPPrinter) 惠普打印机,和(Canon)打印机实现这个接口,然后通过Text作为程序的入口。
建立一个Text 的主程序入口调用
编译输出结果:
上面的Text 知识模拟一个设备而已,如果有多个设备,就会产生重复代码,而面向对象就是需要消除重复代码。那我们把重复代码打包成一个函数?
异常:中断了正常指令流的事件;是在程序运行的时候产生的(编译已经通过);
实例:异常是如何发生的?
一个简单的例子,语法没有错误:
但是在运行Text 的时候出现了异常(异常在运行产生)
再次修改,看是整个Text 不运行,还是被中断了:
可以看到“1”被打印出来,而 “2” 没有打印(说明是被中断)
异常的处理
小结:1.程序员对Error无能为力,只能处理Exception
2.对异常的处理关系到系统的健壮性能
3.使用 try...catch...finally 来处理可能出现的异常代码。
编译可以通过,但是运行出现错误:
我们修改一下User.java:
再次编译,编译没有办法通过:
小提示:
使用命令行编译运行java代码,编译时出现 “编码GBK的不可映射字符” 的错误提示,并且需输出的中文全部变为乱码,此时有两种解决方法:
(方法一)
在输入 javac 命令时,额外输入 -encoding utf-8, 例如:如果编译的源文件名为 Test.java ,那么编译时原先只需输入
javac Test.java,而现在需要输入 javac -encoding utf-8 Test.java
(方法二)
使用 EditPlus 软件编写代码时,通过修改相关设置然后保存文件即可,具体操作如下:
Document菜单---File Encoding---Convert Encoding...----ANSI,OK后保存文件 (需要保存文件,才能使设置生效),然后编译时就无需像(方法一)那样添加 -encoding utf-8 了,可以直接 javac Test.java
再次修改User.java
再次编译User.java,编译通过
编译 Text.java时出现问题
这时我们就可以用 try..catch 来处理异常了:
15.2.IO的分类方法
第一种分发:
1.输入流
2.输出流
第二种分发:
1.字节流
2.字符流
第三种分发:
1.节点流
2.处理流
ImputStream:
int read(byte[ ]b,int offset, int len) ------>返回读取的读取的字节数,读完数据返回:-1
OutoutStream:
void Write(byte[ ]b,int offset,int len)
例子:
新建一个文档:from.txt 和 to.txt
from.txt的内容为,路径为 g:/src/from.txt:
运行Text.java :
把数字转换成字符:
运行结果:
新建一个 to.txt ,文本为空,路径为 g:/src/to.txt.
运行后查看 to.txt:
小结:1.I/O系统的主要目标是为了对数据进行读写操作。
2.数据的流向以Java程序为参照物。
3.I/O可以有三种分类方法。
4.read方法和write方法的用法。
1. 改写from.txt:
修改Text.java,把from.txt的大文件,读取到to.txt中。
运行后,to.txt文本内容和from文本内容一模一样。
字符流:读写文件时,以字符为基础
字节输入流:Reader <-- FileReader
int read(char [] c,int offset,int len)
字节输出流:Writer <--FileWriter
void Write(char [] c,int offset,int len)
运行Text.java
假如使用继承的话我们实现以下功能就会需要一个父类工人(Worker) 用然后水管工(Plumber)和木匠(Carpenter)去实现(implements)工人(Worker) 这个接口 ,然后再用(A公司水管工 )和(B公司水管工 )去都实现水管工(Plumber)这个类,木匠也一样采用继承的方式。目前看似我们建立的类并不多,但我们如果还有电工、水泥工等工总,还有C公司、D公司等公司,类的数量就会成几何增长,没增加一个工总和公司,增加的类就会很多,代码就会变得冗杂。
1.建立一个Worker的父类接口:
2.建立Plumber(水管工)和Carpenter(木匠)去实现工人(Worker)这个接口:
3.接下来就到了精髓的地方了,建立一个Aworker(A公司工人) 这个类也去实现Worker(工人),这样一来水管工(Plumber)、木匠(Carpenter)、和A公司员工(Aworker)全部是 工人(Worker)的子类了,我们同样去实现Worker(工人)这个接口:
4.建立一个 Text01.java 作为程序入口:
我们试运行一下 Text01.java:
目前我们只用了一个接口,三个类就实了A公司的功能(采用继承我们需要的是4个类),看起来好像也差不多?但是我们增加一个公司呢,使用装饰者模式,只需要增加一个类Bworker(采用继承增加两个类,随着工总和公司的增多增加类的数目成倍增长),而使用装设者模式就可以大大简化程序。
细心的可以我们前面使用处理流的时候使用的就是装饰者模式,我们再看看程序:
FileReader 本来只能是几个字节的读取,但是有了bufferedReader之后,就可以一行一行来读取数据,其实就是在FileReader 之上加了新的功能。所以bufferedReader不仅可以修饰FileReader还可以修饰来自键盘和网络的数据!
处理流是用来装饰节点流的,节点流是被装饰者,处理流是装饰者,处理流在为节点流在基础的功能上,添加新的功能。
编译A.java这个文件,会产生两个类文件
如何生成内部类文件的对象?
编译结果验证了内部类可以随意调用外部类的成员变量和成员函数:
例子1:
采用正常的方法,使用装饰者模式:
用Text.java生成 B类的对象,调用成员函数:
运行Text.java
这是正常的逻辑。
例子2:采用匿名内部类的方法
运行的结果也是一样的,只不过,这个生成的类是没有名字的,而且是在别的类里面的类,所以称为 “匿名内部类”。
再看下面一个实现Rnanable接口的例子:不使用匿名内部类方法如下:
使用匿名内部类的方法,一对比就很容易看出端倪啦:
多进程:在操作系统中能(同时)运行多个任务(程序)。
多线程:在同一应用程序中有过个顺序流(同时)执行。
一个应用程序有一个进程,一个进程有多个线程。
注意:线程也是一个对象。有对象就有生成对象的类。
注意:如果上面调用的不是 ft.start( )方法,而是执行ft.run( )就不是多线程,而是单线程运行,结果是:先执行 FirstThread ---->0 -100 然后再执行 main---->0 - 100。
运行Text.java,两个线程无规律运行,谁抢占到CPU使用权,就是谁运行:
下面采用实例演示:
运行Text.java:
——Thread.sleep( x ms); //睡眠醒了进去就绪态,不一定运行
——Thread.yiled(); //当前线程自动让出CPU,但是此线程还会去抢cpu使用权
——getPriority(); //得到当前线程优先级
——setPriority(); //设置当前线程优先级
例子:多线程数据访问出错:
建立一个类 MyThread去实现Runnable 接口:
建立Text.java去调用线程运行:
运行Text.java
如果是卖火车票的话这个数据访问就会出现很大的问题。
运行:前面的问题解决,但是出现新的问题,我们后续解释:
例子:新建一个类 Service.java,这个类有两个函数,全部有同步代码块,且程序会从funA()开始运行,那么就会进去休眠,且这个 this 对象被锁住,在休眠期间,funB也没有办法执行,只有等到funA()执行结束,才会轮到funB,所以说同步代码块,锁住的是对象,而不是特定某一段程序。
再新建两个实现类(MyThread1和MyThread2)去实现Runnable接口(实现线程的第二种方法):
新建Text.java 作为程序入口:
运行程序Text.java,执行java Text 语句后,程序休眠4s,才打印输出以下结果,说明funA()和funB全部被锁住了,更加说明了,同步代码块锁住的是 service 这个对象:
为了进一步验证,我们把,funB() 里面的同步代码块去掉,看程序运行结果:
执行结果,程序一开始就打印出了 ”执行 funB 函数“,然后过4s后才打印 ”执行 funA 函数“,没有加控制代码块的线程,正常运行,不受其他任务控制代码块的影响:
3.二维数组定义方法:
1.类集框架是一组类和接口
2.放置于java.util包当中
3.主要用户存储和管理的对象
4.主要分为三大类:集合、列表和映射
集合(一种存储数据的方式)中的对象不安特定的方式排序,并且没有重复对象。
列表:集合中对象按照索引位置排序,可以有重复的对象
映射 :集合中的每一个元素包含一个键对象和一个值对象,键不可重复,值可以重复。
从上面的集合框架图可以看到,Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。Collection 接口又有 3 种子类型,List、Set 和 Queue,再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap 等等。
1.arrayList.add(参数1 ) //向列表添加数据,参数是需要添加的数据
2.arrayList.remove(参数1) //参数是需要移除数据的索引号
3.arrayList.size() //得到当前列表长度
import java.util.List; //导入包
import java.util.ArrayList;
class Text{
public static void main(String args[]){
//生成ArrayList对象
//和数组不同的是,这个列表不是固定死的长度
//根据你的数据大小调节
//ArrayList 表示列表只能存放Sring类型数据
ArrayList arrayList = new ArrayList();
//向 arrayList 列表添加数据,用 arrayList.add()方法
arrayList.add("a");
arrayList.add("b");
arrayList.add("c");
arrayList.add("d");
//使用arrayList.remove() 方法去除列表的数据
arrayList.remove(2); //参数为索引号,去掉"c"
//取出 arrayList 列表的数据,用arrayList.get()方法
//用 arrayList.size()方法可以获取列表长度
for(int i=0;i
运行结果Text.java:
boolean add(Object o) |
向集合加入一个对象 |
void clear( ) |
删除集合当中所有对象 |
blloean isEmpty( ) |
判断集合是否为空 |
remove(Object o) |
从集合中删除一个对象的引用 |
int size( ) |
返回集合元素的数目 |
一个 例子演示函数用法:
注意:Set 不允许有重复元素,重复的话会被忽略掉
import java.util.Set;
import java.util.HashSet;//导入包
class Text{
public static void main(String args[]){
//称为泛型的声明
HashSet hashset = new HashSet();
//把HashSet的对象向上转型
//子类 HashSet的对象,赋值给父类Set的引用
Set set = hashset; //只能调用Set有的方法
//使用set的方法,增加集合成员
set.add("a");
set.add("b");
set.add("c");
set.add("d");
set.add("d"); //重复元素,被忽略
//集合的个数
int i = set.size();
System.out.println("clear之前set对象的长度"+i);
//清空集合
set.clear();
//再次获取集合个数
i = set.size();
System.out.println("clear之后set对象的长度"+i);
}
}
运行Text.java结果:
import java.util.Set;
import java.util.HashSet;//导入包
import java.util.Iterator;//导入迭代器包
class Text{
public static void main(String args[]){
//称为泛型的声明
HashSet hashset = new HashSet();
//把HashSet的对象向上转型
//子类 HashSet的对象,赋值给父类Set的引用
Set set = hashset; //只能调用Set有的方法
//使用set的方法,增加集合成员
set.add("a");
set.add("b");
set.add("c");
set.add("d");
set.add("d"); //重复元素,被忽略
//调用Set对象的Iteractor方法,会生成一个迭代器对象,该对象用于遍历整个Set
//需要使用泛型声明
Iterator it = set.iterator();
// 使用it.hasNext() 方法返回一个bollean类型数值
while(it.hasNext()){
//使用it.next()方法获取游标下一个元素的值
String s = it.next();
System.out.println(s);
}
}
}
映射 (Map):集合中的每一个元素包含一个键对象和一个值对象,键不可重复,值可以重复。
注意:JdK API帮助文档是我们非常重要的工具,里面详细介绍了API函数的用法。
在线帮助文档地址:点我查看JDK帮助文档
我们看一看Map的帮助文档,里面的解释非常详细和权威:
最重要的方法摘要:
咋们用一个简单的例子,调用一下这个函数:
import java.util.Map;
import java.util.HashMap;
class Text{
public static void main(String args[]){
//指定泛型,两个对象,键值对,两个对象
HashMap hashMap = new HashMap();
//向上转型为Map类型
Map map = hashMap;
//就可以使用map的put方法了
map.put("1","a");
map.put("2","b");
map.put("3","c");
map.put("4","d");
map.put("3","f"); //键值没有办法重复,键值为3的值会被"f"覆盖
//使用map.size()方法返回此映射中的键-值映射关系数。
int i = map.size();
System.out.println(i);
//使用map.get()方法,返回指定键所映射的值;
//如果此映射不包含该键的映射关系,则返回 null
String s = map.get("3");
System.out.println(s);
}
}
运行Text.java:
我们可以在java安装的文件夹里的 Object.java中找到 equals函数的原形
那么在 equals函数中“==”的作用是什么?
操作符的作用:判断这个两个引用是否指向堆内存当中的同一个地址 (对象)
例子1:
调用equals函数,:
如果没有去复写 equals函数 ,和直接调用 “==”是完全一样的:
注意:User已经是继承了Object的
运行结果和我们预想的一样:
小结:如上所述,如果这个原型equals( ) 函数只能去判断,两个引用是否指向同一个对象,如果指向同一个对象就返回 ture,否则返回 false.而并不能去比较在同一个类指向不同对象的内容是否相等。像上图所示,虽然 u1指向的对象和 u3指向的对象内容是一样的,但是在堆内存中指向的不是同一个对象,随意判定为 false.
例子2:我们试一下比较,指向不同对象,但是内容相同的对象,进行比较,看是否能得到我们想要的结果:
运行Text.java,可见和我们预想的一样,一旦指向不同对象,不管你的内容是否一样,我都返回false:
什么是对象的内容相等?
1.对象的类型相同(可以使用instenceof操作符进行比较)。(比如是否都为 User类,如果类不同,肯定不能比较了)。
2.两个对象的成员变量的值完全相同(比如在User类有两个变量 name 和 age)。
我们依照这两个条件在User.java中复写这个 equals() 这个方法:
class User{
String name; //因为 String是引用数据类型,不能用equals进行比较内容,
int age; //基本数据类型用 “==” 进行比较
//复写 equals 函数
public boolean equals(Object obj){
//this 就是调用equals函数的那个对象
//谁能调用这个equals呢?属于User这个类,this就是User类型的。
//所以只有User类的对象可以调用equals这个函数
if(this == obj){ //如果在堆内存中指向同一个对象,内容一定相等
return true; //直接返回真
}
//那 obj 是属于User类型的吗?
//instanceof 关键字用于判断前面的对象是不是后面的那种类型
//是的话返回真,否返回假
boolean b = obj instanceof User;
if(b){ //那么说明obj也是User类型
//那么需要把 obj 向下转型为 User的对象
//向下转型,能成功,因为我们知道 obj 这个对象是 User这个类生出的
//在前面这个 obj 之所以是 Object 类型,是因为有过一次向上转型
//现在把它转回来也是 ok 的
User u = (User)obj;
//接下来判断 u 对象和 this 他们成员变量的值是否相等
//这里调用的 String类型equals()方法不是本函数的
if(this.age == u.age && this.name.equals(u.name)){
return true; //那就是相等的
}
else{
return false;
}
}
else{
return false; //如果不是的话,就不用比较了
}
}
}
然后在Text.java 引用3个创建 User 的对象进行比较内容:
class Text{
public static void main(String args[]){
//创建u1、u2、u3的引用
User u1 = new User();
User u2 = new User();
User u3 = new User();
u1.name = "zhangsan";
u1.age = 12;
u2.name = "lisi";
u2.age = 12;
u3.name = "zhangsan";
u3.age = 12;
System.out.println("u1和u2的比较结果是:" + u1.equals(u2));
System.out.println("u1和u3的比较结果是:" + u1.equals(u3));
}
}
运行Text.java,输出结果:
什么是Hash算法?
Hash算法的特点,可以根据唯一的散列值直接找到输入:
class User{
String name;
int age;
//新增两个构造函数
public User(){
}
public User(String name,int age){
this.name = name;
this.age = age;
}
public boolean equals(Object obj){
if(this == obj){
return true;
}
boolean b = obj instanceof User;
if(b){
User u = (User)obj;
if(this.age == u.age && this.name.equals(u.name)){
return true;
}
else{
return false;
}
}
else{
return false;
}
}
}
import java.util.*; //导入包
class Text{
public static void main(String args[]){
User u = new User("zhangsan",20);
//声明HashMap对象,指明泛型为
HashMap map = new HashMap();
//向map对象put
map.put(u,"abcd");
//用equals比较new User("zhangsan",20)和 u 的结果应该为true
System.out.println("比较结果是:" + new User("zhangsan",20).equals(u));
//根据键得到值
String s =map.get(new User("zhangsan",20));
System.out.println(s);
}
}
class User{
String name;
int age;
//新增两个构造函数
public User(){
}
public User(String name,int age){
this.name = name;
this.age = age;
}
public boolean equals(Object obj){
if(this == obj){
return true;
}
boolean b = obj instanceof User;
if(b){
User u = (User)obj;
if(this.age == u.age && this.name.equals(u.name)){
return true;
}
else{
return false;
}
}
else{
return false;
}
}
//对于不同的对象生成hashcode的数值是不一样的
//对于用equals相比结果为ture的对象来讲hashCode是一样的
//因为为true则,name和age肯定是一样的,那么返回result的值肯定是一样的
public int hashCode(){
int result = 17; //初始值为除0外的素数
result = 31 * result + age;
result = 31 * result + name.hashCode(); //调用String的hashCode方法
return result;
}
}
import java.util.*; //导入包
class Text{
public static void main(String args[]){
User u = new User("zhangsan",20);
//声明HashMap对象,指明泛型为
HashMap map = new HashMap();
//向map对象put
map.put(u,"abcd");
//用equals比较new User("zhangsan",20)和 u 的结果应该为true
System.out.println("比较结果是:" + new User("zhangsan",20).equals(u));
//根据键得到值
String s =map.get(new User("zhangsan",20));
System.out.println("得到的键值为:"+s);
}
}
以下代码的运行结果:System.out.println("abc") ------>打印 abc 字符
那么下面两行呢?
User u = new User();
System.out.println(u);
class User{
String name;
int age;
//新增两个构造函数
public User(){
}
public User(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
String s = "name:"+name+", age:"+age;
return s;
}
}
import java.util.*; //导入包
class Text{
public static void main(String args[]){
User u = new User("zhangsan",20);
//当你打印一个字符串的时候,首先会调用这个类的toSring方法
System.out.println(u);
}
}
工作区是一个目录,程序和程序所需要用到的资源都在workspace里,中间缓存文件也存在工作区中。
为一个需求所服务的代码文件,一个workspace 可以拥有个项目,而你的代码必须有归属于某个项目的,不能单独存在。
首先,创建项目,弹出一个窗口:
Alt + "/" 快捷键的用法:
此时如果我还想生成一个Student的对象,但是写到一半,不想写了,我们直接使用快捷键:会弹出提示窗口,显示所有以stu开头的函数:
我们可以在 Edit菜单栏可以看到快捷键:
例子:我们编辑Student.java 文件如下,我们新建了三个成员变量,现在我们想新建两个构造函数,一个是无参数构造函数,一个是带三个参数的构造函数,如何让Eclipse 自动帮我们去生成呢:
操作上面的结果是:
很方便就帮我们复写了这两个函数:
选中需要注释的代码,然后快捷键:Ctrl + "/".
取消注释:选中已经被注释的代码,同样快捷键:Ctrl + "/"
1.在别改变代码功能和性能的基础上。
2.改善软件的设计增加可读性
3.协助找到bugs
4. 提升开发效率
1.修改类名
例子:在以下工程中,我们如果想改变Person的为Teacher,怎么办呢?
如果手动改动的话,麻烦不说,只有有一个地方忘了程序就会出现错误,降低了开发效率,但是我们可以使用Eclipse代码重构功能。
2.移动:如何把一个包里面的类或接口移动到另一个包呢?
3.修改方法签名:
例子:比如我们在Student.java中创建了一个函数 ,void speak() 然后在 void eat() 中调用,突然我们想改变speak为talk,如果多个地方调用这个方法的话就会很麻烦,我们用Eclipse修改方法签名就会很简单:
如果此时我们想把 talk( )函数推到Teacher(父类)中,怎么办?
4.抽取类功能:把在一个类的方法,给抽到另一类当中
例子:我们把 Student中的抽取 talk方法和eat 方法,抽成父类,抽好了以后,Student,应给去继承有着两个函数的类或者接口。
在Person.java中已经有着两个方法了:
在Student.java中没哟这两个方法了:
也可以抽取成毫无关系的类。
5.抽取方法:减少重复代码
例子:如下、
我们不希望重复代码,我们可以把这两句抽成一个方法,然后别的函数再调用这个方法: