Java基础,
Java基础,
Java基础
安装JAVA的开发环境
第一步、下载JDK,下载地址:
JDK官网下载地址:
http://www.oracle.com/technetwork/java/javase/downloads/index.html。
提示:一定要下载系统类型对应的JDK(32位或者64位,否则会出现安装异常)。
第二步、安装JDK:
将JDK安装到根目录(注:安装目录的路径中不要有空格,否则会出问题的)。
第三步、配置JDK的环境变量:
打开“开始—>计算机—>属性—>高级系统设置—>环境变量”。
1.JAVA_HOME:JDK安装的全路径;
2.PATH:%JAVA_HOME%\bin;
3.CLASSPATH:.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar
环境变量就是给windows查找命令指路的,让windows能够找到可执行的命令。
第四步、检验环境安装情况:
使用快捷键“Win+R”,打开运行窗口,输入cmd,回车;
1.在控制台上输入:java
2.在控制台上输入:javac
如果输入以上两个命令,未出现异常信息,表示安装JDK成功!
编译和运行JAVA代码
使用javac编译java文件和java命令运行代码。
1.在dos界面用cd命令进入java文件所在的目录。
2.在dos界面中输入javac + java文件名(文件名带扩展名一起)。
3.继续在dos界面中输入java+java文件名(注:不能带扩展名)。
释:javac命令:编译java文件,并且生成class文件;
Java命令:运行java代码。
JDK安装目录简介
bin:该路径下存放了JDK的各种工具命令,常用的java、javac等命令就存放在该路径下。
db:该路径就是安装Java DB的路径。
jre:该路径下安装的就是运行Java程序所必需的JRE环境。
lib:该路径下存放的是JDK工具命令的实际执行程序。
src.zip:该压缩文件里存放的就是Java所有核心类库的源代码。
README和LICENSN等说明性文档。
JDK与JRE
JDK的全称是Java SE Development Kit,即Java标准版开发包,是sun公司提供的一套用于开发Java应用程序的开发包,它提供了编译、运行Java程序所需要的各种工具和资源,包括Java编译器。Java运行时环境,以及常用的Java类库等。
Java运行时环境,它的全称是Java Runtime Environment,因此也被称为JRE,它是运行Java程序的必需条件。
JAVA的虚拟机JVM
JVM(Java Virtual Machine)。JVM是可运行Java字节码文件的虚拟计算机。所有的平台上的JVM向编译器提供相同的编程接口,而编译器只需要面向虚拟机,生成虚拟机能理解的代码,然后由虚拟机来解释执行。
JAVA是如何实现跨平台的?
JVM是Java程序跨平台的关键部分,只要为不同平台实现发相应的虚拟机,编译后的java字节码就可以在该平台上运行。显然,相同的字节码程序需要在不同的平台上运行,这几乎是“不可能的”,只有通过中间的转换器才可实现,JVM就是这个转换器。
提示:也可以认为JVM分向上和向下两个部分,所有平台上的JVM向上提供给JAVA字节码程序的接口完全相同,但向下适应不同平台的接口则互不相同。
JVM与JRE的关系
不是说JVM是运行Java程序的核心虚拟机,而运行Java程序不仅需要核心虚拟机,还需要其他的类加载器、字节码校验器以及大量的基础类库。JRE除了包含JVM之外,还包含运行java程序的其他环境支持。
JVM和JAVA跨平台特性
JDK&JRE&JVM
标识符identifier A
作用:给变量、类和方法命名。
Java标识符有如下命名规则:
①标识符必须以字母、下划线、美元符$开头。
②标识符其它部分可以是字母、下划线、美元符$和数字的任意组合。
③Java标识符对大小写敏感,且长度无限制。
④不可以是Java的关键字。
注:Java不采用通常语言使用的ASCII字符集,而是采用unicode这样的国际通用字符集。因此,这里的字母的含义:英文、汉字等等。(不建议大家使用汉字来定义标识符!)
不合法的标识符:
int 1a=3; //不能用数字开关。
int a#=3; //不能包含#这样的特殊字符。
int int=3;//不能使用关键字。
字符集简介
ISO8859-1:西欧字符集。
BIG5:台湾的大五码,表示繁体汉字。
GB2312:大陆使用最早、最广的简体中文字符集。
GBK:GB2312的扩展,可以表示繁体中文。
GB18030:最新GBK的扩展,中国所有非手持/嵌入式计算机系统的强制实施标准,可以表 示汉字,维吾尔、藏文等中华民族字符。
Unicode:国际通用字符集。
Java数据类型
Java是一种强类型语言,每个变量都必须声明其类型。
整型变量
Java语言整型常数的三种表示形式:
十进制整数,如:99,-500,0
八进制整数,要求以0开头,如:015
十六进制整数,要求以0X或0x开头,如:0X15
Java语言的整型常数默认为int型,声明long型常量可以在后面加“l”或“L”(建议使用大写,小写容易误认为数字1),如:
long a=20_0000_0000; //不出错,在int表示的范围内(21亿)。
long b=200_0000_0000; //不加“L”出错,已经超出int表示的范围。
类型 |
占用存储空间 |
表数范围 |
默认值 |
byte |
1字节 |
-128~127 |
0 |
short |
2字节 |
-215 ~ 215-1(-32768~32767) |
0 |
int |
4字节 |
-231 ~ 231-1(约-21.4亿~21.4亿) |
0 |
long |
8字节 |
-263 ~ 263-1 |
0 |
更大的整数:BigInteger
数字转换
Integer.toBinaryString(n) //转二进制字符串
Integer.toOctalString(n) //转八进制字符串
Integer.toHexString(n) //转十六进制字符串
浮点型变量
float类型又被称作单精度类型,尾数可以精确到7位有效数字,在很多情况下,float类型的精度很难满足需求。
double表示这种类型的数值精度是float类型的两倍,又被称作双精度,绝大部分应用程序都采用double类型。
Java浮点类型常量有两种表示形式——
十进制形式,例如:
3.14 314 0.314
科学记数法形式,如:
314e2 314E2 314E-2
double d=314e2; // 314*102 -->31400.0
double d2=314E-2; // 314*10-2 -->3.14
浮点数值默认为double类型。要将其变为float类型,需要在后面增加F/f如:3.14F
类型 |
占用存储空间 |
表数范围 |
默认值 |
float |
4字节 |
-3.4028235E38 ~ 3.4028235E38 |
0 |
|
|
0.8E-45 ~ 1(小数的表数范围) |
|
double |
8字节 |
-1.797693E308 ~ 1.797693E308 |
0 |
|
|
2.5E-324 ~ 1(小数的表数范围) |
|
Boolean |
1字节 |
true/false |
false |
Char |
2字节 |
0 ~ 65535 |
\u0000 |
float f=3.14F;
更大的浮点数BigDecimal
浮点数存在舍入误差,很多数字不能精确表示。如果需要进行不产生舍入误差的精确数字计算,需要使用BigDecimal。
自动类型转换A
容量小的数据类型可以自动转换为容量大的数据类型。
int i=3;
double d=i;
float f=i;
double d2=f;
特例:可以将整型数值直接赋值给byte、short、char等类型变量,而不需要进行强制类型转换,只要不超出其表数范围。
short b=12; //合法
short b2=1234567; //不合法
自动类型转换B
在图中,黑色实线表示无数据丢失的自动类型转换,而红色虚线表示在转换时可能会有精度的损失。
强制类型转换
如果希望把表数范围大的变量赋值给另一个表数范围小的变量时,则必须进行强制类型转换,强制类型转换的语法格式:
小类型 变量名 = (小类型)大类型变量;
强制类型转换的运算符是圆括号()。我们也称强制转换为“缩小转换”。
变量
Java是一种强类型语言,每个变量都必须声明类型。
变量是Java语言中的基本存储单位,它是用来存储信息的。
变量在使用前必须对其声明,只有在变量声明以后,才能为其分配相应长度的存储单元,声明格式为:
type varName = value;
type varName;
命名规范:首字母小写、驼峰原则、不能用非法字符。
常量
final type NAME = value;
以final关键字修饰。只能被初始化一次!
命名规范:全部用大写字母,多个单词用下划线分隔。例:MAX_ONE
关键字
除了48个关键字之外,Java还包含goto和const两个保留字(reserved word),保留字的意思是,Java现在还未使用这两个mn单词作为关键字,但可能在未来的Java版本中使用这两个单词作为关键字;不仅如此,Java还提供了3个特殊的直接量(literal):true、false和null;Java语言的标识符也不能使用这两个保留字和三个特殊的直接量。
运算符
运算符是一种特殊的符号,用以表示数据的运算、赋值和比较等。Java语言使用运算符将一个或多个操作数连缀成执行语句,用以实现特定功能。
Java语言中的运算符可以分为:算术运算符、赋值运算符、比较运算符、逻辑运算符、位运算符、类型相关运算符。
算术运算符
算术运算符包括+、-、*、/、%、++、--、/
/:除法运算符。除法运算符有些特殊,如果除法运算符的两个操作数都是整数类型,则计算结果也是整数,就是将自然除法的结果截断取整。如果除法运算符的两个运算符都是整数,则除数不能为0,否则将引发除以零异常[java.lang.ArithmeitcException:/by zero]。
如果除法运算符的两个操作数有一个或两个浮点数,则计算结果也是浮点数,这个结果就是自然除法的结果。而且此时允许除数是0,或者0.0,得到的结果是正无穷大或负无穷大。
赋值运算符
赋值运算符用于为变量指定变量值,java使用=作为赋值运算符。通常,使用赋值运算符将一个常量赋给变量。也可以将一个变量的值赋给另一个变量。主要包括(+=、-=、*=、/=、%=)。
值得指出的是,赋值表达式的值就是右边被赋的值。例如String str2 = str表达式的值就是str。因此,赋值运算符支持连续赋值,通过使用多个赋值运算符,可以一次为多个变量赋值。a=b=c=7;
赋值运算符还可用于将表达式的值赋给变量。
比较运算符
比较运算符用于判断两个变量或常量的大小,比较运算的结果是一个布尔值(true或false)。Java支持的比较运算符:
>大于 >=大于等于
<小于 <=小于等于
==等于 !=不等于
==:等于,如果进行比较的两个操作数都是数值类型,即使它们的数据类型不相同,只要它们的值相等。也都返回true。Java也支持两个Boolean类型的值进行比较,例如true==false将返回false。
!=:不等于,如果进行比较的两个操作数都是数值类型,无论它们的数据类型是否相同。都返回true。
逻辑运算符
逻辑运算符用于操作两个布尔型的变量或常量。
逻辑运算符主要有以下6个。
&&:逻辑与,前后两个操作数必须都是true才返回true,否则返回false。
&:不短路与,作用和&&相同,但不会短路。
||:逻辑或,只要两个操作数中有一个true,就可以返回true,否则返回false。
|:不短路或,作用与||相同,但不会短路。
!:逻辑非,只需要一个操作数,取反。
^:异或,当两个操作数不同时才返回1,如果两个操作数相同则返回0。
适中:&&和&的区别:与操作分两种,一种是普通与(&),另外一种是适中与(&&),区别:
1.&:表示所有的判断条件都要执行,不管前面是否满足判断条件;
2.&&:如果前面的条件已经是false了,那么后面的条件不需要再进行任何的判断,这就叫短路。
||跟|同理↑
位运算符
Java支持的位运算符有如下7个:
&:按位与
|:按位或
~:按位非
^:按位异或
<<:左移运算符
>>:右移运算符
>>>:无符号右移运算符
三目运算符
int a=expression ? true值 : false值;
注意:使用三目运算符时,必须要定义一个变量接收执行的结果!
程序的三种基本结构
顺序结构、选择结构、循环结构
判断
switch分支语句
switch语句由一个控制表达式和多个case标签组成,和if语句不同的是,switch语句后面的控制表达式的数据类型只能是byte、short、int、char四个整型和枚举类型,不能使用Boolean类型。Java7改进了switch分支语句,Java7允许switch语句中的控制表达式为tring类型。
switch语法
switch语句往往需要在case标签后紧跟一个代码块,case标签作为这个代码块的标识。switch语句的语法格式如下:
switch(变量){
case 值1:语句1; break;
case 值2:语句2;
case 值3:语句3;
default: false语句;
}
释:当变量的值等于值1时,执行语句1,然后执行break打断。如果变量的值等于值2时,执行语句2,并往下一直执行,包括default语句也会被执行,除非被break打断或continue跳过。与if判断不同的是default分支语句可以在分支语句的第一行,而if判断的else分支语句只能写在最后。
注:switch语句后的expression表达式的数据类型只能是byte、short、int、char和枚举、string(JDK7以上才支持)类型;
if判断——
if(条件1){
语句1;
}else if(条件2){
语句2;
}else{
false语句;
}
释:满足条件1执行语句1;满足条件2执行语句2;else if可以有无数个,如果都不满足则执行false语句。
循环
for循环——
for(声明变量;判断条件;迭代语句){
循环体语句;
}
执行顺序:声明变量(只在首次循环时执行)→判断条件→循环体语句→迭代语句
注:迭代语句其实也是语句,只不过是最后执行罢了。
while循环——
int i=0;
while(i<2){
System.out.print(“a”);
i++;
}
do while循环——
int i=0;
do{
System.out.print(“a”);
i++;
}while(i<2);
while与do while的不同点:while循环是先判断再执行循环体语句。do while循环是先执行循环语句再判断。
while与do while的共同点:当判断条件不成立时都会立刻终止整个循环。
注:while与do while的区别,首次循环while循环不满足条件时会直接结束,而do while首次循环不满足条件时会执行循环体语句一次。
循环体的常用命令
continue——跳过本次循环;
continue语句不仅可以跳过其所在的循环,还可以直接跳过其外层循环。此时需要在continue后紧跟一个标签,这个标签用于标识一个外层循环。
int index = 0;
c:
while(index!=3){
index++;
for(int i=0;i<4;i++){
if(i==2){
continue c;
}
System.out.println(i);
}
}
break——终止整个循环;
break语句不仅可以结束其所在的循环,还可以直接结束其外层循环。此时需要在break后紧跟一个标签,这个标签用于标识一个外层循环。
int index = 0;
c:
while(index!=3){
index++;
for(int i=0;i<4;i++){
if(i==2){
break c;
}
System.out.println(i);
}
}
使用return结束方法
return关键字并不是专门用于结束循环的,return的功能是结束一个方法。当一个方法执行到一个return语句时(return关键字后还可以跟变量、常量和表达式,这将在方法介绍中有更详细的解释),这个方法将被结束。
数组
数组介绍
数组是编程语言中最常见的一种数据结构,可用于存储多个数据,每个数组元素存放一个数据,通常可通过数组元素的索引来访问数组元素,包括数组元素赋值和取出数组元素的值。
数组特征
1.数组要求数组里的所有元素具有相同的数据类型。
2.数组一旦初始化完成,数组在内存中所占的空间将固定下来,因此数组的长度不可改变。
3.数组不仅可以存储基本类型的数据,也可以存储引用类型的数据。
4.数组也是一种数据类型,它本身是一种引用类型。
定义数组
Java语言支持两种语法格式来定义数组
int[] arr; //类型[]变量名;
int arr[]; //类型 变量名[];
注意:数组是一种引用类型的变量,因此使用它定义一个变量时,仅仅表示定义了一个引用变量(也就是定义了一个指针),这个引用变量还未指向任何有效的内存,因此定义数组时不能指定数组的长度。而且由于定义数组只是定义了一个引用变量,并未指向任何有效的内存空间,所以还没有内存空间来存储数组元素,因此这个数组也不能使用,
数组的初始化
Java语言中数组必须先初始化,然后才可以使用。所谓初始化,就是为数组的数组元素分配内存空间,并为每个数组元素赋初始值。数组的初始化有如下两种方式:
静态初始化:初始化时由程序显示指定每个数组元素的初始值,由系统决定数组长度。
动态初始化:初始化时程序员只指定数组的长度,由系统为数组分配初始值。
静态初始化
int[] array = new int[]{1, 2}; //类型[] 变量名= new 类型[]{元素1,元素2};
或int[] array={1,2}; //类型[] 变量名={元素1,元素2};
动态初始化
动态初始化只指定数组的长度,由系统为每个数组元素指定初始值。动态初始化的语法格式如下:
int[] array=new int[3]; //类型[] 变量名=new类型[length];
系统按如下规则分配初始值:
byte、short、int、long分配初始值为0
float、double分配初始值为0.0[
char分配初始值为’\u0000’
Boolean分配初始值为false
引用类型的数组分配初始值为null
数组元素相当于对象的成员变量
访问数组实例
使用for循环迭代数组:
int[] array={10, 20, 50, 100};
for(int i=0;i<array.length;i++){
int temp=array[i];
System.out.println(temp);
}
访问数组注意事项
如果访问数组元素时指定的索引值小于0或者大于等于数组的长度,编译程序不会出现错误,但运行时会抛出异常:java.lang.ArrayIndexOutOfBoundsException:N(数组索引越界异常)。
foreach循环
从JDK5之后,java提供了一种更简单的循环:foreach循环,这种循环遍历数组和集合更加简洁。使用foreach循环遍历数组和集合元素时,无须获得数组和集合长度,无须根据索引来访问数组元素和集合元素,foreach循环自动遍历数组和集合的每个元素。foreach循环的语法如下:
for(type variableName: array | collection){
//variableName自动迭代访问每个元素
}
int[] array={1, 2, 3};
for(int temp:array){
System.out.print(temp+" ");
} //==>输出1 2 3
在上面语法格式中,type是数组元素或集合元素的类型,variableName是一个形参名,foreach循环自动将数组元素、集合元素依次赋给该变量。
注:使用foreach循环迭代数组元素时,并不能改变数组元素的值,因此不要对foreach的循环变量进行赋值。
冒泡排序
int[] arr={1, 23, 435, 34, 76};
for(int i=0;i<arr.length;i++){
for(int j=i+1;j<arr.length;j++){
if(arr[i]>arr[j]){//从小到大;
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
}
System.out.print(Arrays.toString(arr));
去重复
int[] array={10, 0, 10, 8, 5};
int now=0;
int[] newArray=new int[4];
for(int i=0;i<array.length;i++){
for(int j=0;j<now+1;j++){
if(j==now){
newArray[now]=array[i];
now++;
}
if(array[i]==newArray[j]){
break;
}
}
}
for(int i=0;i<newArray.length;i++){
System.out.println(newArray[i]);
}
取数组的最大值和最小值
int[]arr = {10,15,5,60};
int max=arr[0];
int min=arr[0];
for(int i=1;i<arr.length;i++){
if(max<arr[i]){
max=arr[i];
}
if(min>arr[i]){
min=arr[i];
}
}
System.out.println(max+"\t"+min);
数组元素复制
将一个数组中元素复制到另外一个数组中。实现数组复制方式有两种:
使用Arrays.copeOf方法实现:
import java.util.Arrays;//需要导入一下util包
int[] array = {10,15,60,18,30};
int[] newArray=Arrays.copyOf(array,array.length/*新数组的长度*/);
for(int i=0;i<newArray.length;i++){
System.out.print(newArray[i]+" ");
}
使用for循环复制:
int[]array = {10,15,60,18,30};
int[]newArray2=new int[array.length];
for(int i=0;i<newArray2.length;i++){
newArray2[i]=array[i];
}
删除数组元素
int[] array = {100, 50, 19, 120, 500, 1000};
int num=100;
int[] newArray=new int[array.length];
int now=0;
for(int temp:array){
if(temp!=num){
newArray[now]=temp;
now++;
}
}
for(int temp:newArray){
System.out.println(temp);
}
实现无限增长的数组
public static int[] add(int[]a,int b){
int[] temp=new int[a.length+1];
for(int i=0;i<a.length;i++){
temp[i]=a[i];
}
temp[a.length]=b;
return temp;
}
二维数组定义
静态定义:
int[][] array={
{1, 2},
{3, 4}
};
动态定义:
int[][] array= new int[2][2];
或int[][] array2= new int[2][];
array2[0]=new int[2];
array2[1]=new int[2];
面向对象
对象和类的概念
OOD面向对象设计、OOA分析对象、OOP编码
面向对象编程(OOP)的本质——
以类的方式组织代码,以对象的方式封装(组织)数据。
面向对象思维:OOA、OOD
对象——是具体的事物
类——是对对象的抽象(抽象 抽出象的部分)
先有具体的对象,然后抽象各个对象之间象的部分,归纳出类,通过类再认识其他对象。
内存分析
栈:存放局部变量
堆:存放new出来的对象
方法区:存放类的信息(代码)、static变量、static方法、常量池(字符串常量)等。
对象和类的总结
√对象和类的关系:特殊到一般,具体到抽象。
√类:我们叫做class。
√对象:我们叫做Object,instance(实例)。以后我们说某个类的对象和某个类的实例,是 一个的意思。
√类可以看成一类对象的模板,对象可以看成该类的一个具体实例。
√类是用于描述同一类型的对象的一个抽象的概念,类中定义了这一类对象所应具有的静态 和动态属性。
√对象是Java程序的核心,在Java程序中“万事万物皆对象”。
√JDK提供了很多类供编程人员使用,编程人员也可以定义自己的类。
static关键字
在类中,用static声明的成员变量为静态成员变量,或者叫做类属性,类变量。
1.它为该类的公用变量,从属于类,被该类的所有实例共享,在类被载入时被显式初始化。
2.对于该类的所有对象来说,static成员变量只有一份,被该类的所有对象共享!
3.可以使用“对象.类属性”来调用。不过,一般都是用“类名.类属性”。
用static声明的方法为静态方法
1.不需要对象,就可以调用(类名.方法名)。
2.在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可访问非static的成员。
static关键字的一些特性:
1.修饰类的内部类,不能被其他外部类直接访问。
2.修饰的方法为静态方法,调用该方法语法是:类名.方法([实参])。
3.修饰的变量为静态变量,调用该变量语法是:类名.变量([实参])。
4.static修饰初始化块为静态块,当类被加载时,自动调用。
5.static修饰的方法中不能使用关键字this和super。
6.static和abstract不能同时修饰方法。
7.static修饰的方法,不能被重写。
变量
静态成员变量通过static关键字修饰
static int num=123;
静态成员变量从属于类,可以通过“类名.变量名”直接调用。调用时需要考虑该变量是否被修改过,是否影响自己的编码。
实例成员变量和局部变量从属于实例(对象),只有该类创建实例才会被声明和初始化,可以通过“实例.变量名”调用。每次创建一个实例都生成新的初始化成员变量和局部变量。
方法
1.概念:方法(js的函数):将相同的代码块放到方法里,可以起到重复使用。减少代码量,利于维护,业务逻辑更加清晰
2.定义语法:
[权限修饰符] [static]返回值类型 方法名([形参])
3.方法的分类:
a.静态方法(类方法):在返回值类型前面添加static关键字修饰。
注意:在同一个类中,其他的方法调用静态方法,语法:方法名([实参]);
在不同类中,调用静态方法,语法:类名.方法名([实参]);
b.实例方法:不使用static修饰
4.总结:
a.静态方法不能调用实例的方法和实例的成员变量,需要创建对象
b.实例的方法可以调用静态的方法和静态的全局变量
c.实例方法可以直接调用实例的全局变量
形参: 定义在方法名后面的括号中,接收实参传递的值(地址)
语法: 方法名(类型 参数名, ...,类型 参数名n)
实参: 传递具体的值或者是地址。
变长参数:当前实参的个数不确定时,可以使用变长参数
语法: 方法名(类型...变量名)
public int test(int... args){
return args[0]+args[1];
}
public static void main(String[]args) {
System.out.println(new Temp12().test(1, 2));
}
注意:一个方法只能有一个变长参数,而且必须在最后
提示:
1.在参数传递过程中,八大基本类型传递是值,而引用传递的是地址
2.实参类型的值和形参类型一定要相同
构造器A
构造器又称为构造方法,constructor
构造器用于构造该类的实例。
格式如下:
[修饰符]类名(形参列表){
//n条语句
}
构造器是一种特殊的方法:
①通过new关键字调用!
②构造器虽然有返回值,但是不能定义返回类型(返回值的类型肯定是本类),不能在构造器里调用return。
③如果我们没有定义构造器,则系统会自动定义一个无参的构造函数。如果已定义则 编译器不会添加!
④构造器的方法名必须和类名一致!
⑤作用:构造该类的对象,经常也用来初始化对象的属性。
⑥构造器的权限修饰符跟new对象有关,比如以private修饰则该类不能在其他类中new对象。
重载(Overload)A
方法的重载是指一个类中可以定义有相同的名字,但参数不同的多个方法。调用时,会根据不同的参数定义不同的多个方法。
两同三不同
——同一个类,同一个方法名。
——不同:参数列表不同(类型,个数,顺序不同)
只有返回值不同不构成方法的重载
只有形参的名称不同,不构成方法的重载
与普通方法一样,构造方法也可重载
初始化块
静态初始化块
1.语法:
static{
//代码块
}
2.调用的时间:
当类被加载的时候,静态初始化块被自动调用
非静态的初始化块
1.语法:
{
//代码块
}
2.调用的时间:
创建对象的时候调用
3.与构造器比较:
a.两者都在是创建对象时调用
b.非静态的初始化块比构造器先调用
注意:初始化块和构造器,都是自动调用
类加载成员的顺序:
1.加载静态的
2.执行main方法
3.当在main方法中创建对象时
4.执行非静态的初始化块
5.构造器
实例的成员变量和非静态初始化块,谁在最前面谁被加载。
实例的成员变量,只有定义在非静态初始化块前面,才能被非静态初始化块使用
内部类(innerclasses)
一般情况,我们把类定义成独立的单元。有些情况下,我们把一个类放在另一个类的内部定义,称为内部类。
内部类的作用:
1.内部类提供了更好的封装。只能让外部类直接访问,不允许同一个包中的其他类直接访问。
2.内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员。但外部类不能访问内部类的内部属性。
内部类的使用场合:
由于内部类提供了更好的封装特性,并且可以很方便的访问外部类的属性。所以,通常内部类在只为所在外部类提供服务的情况下优先使用。
内部类的分类:
1.成员内部类(可以使用private、protected、public任意进行修饰。类文件:外部类$内部类:class)
a)非静态内部类(外部类里使用非静态内部类和平时使用其他类没什么不同)。
ⅰ非静态内部类必须寄存在一个外部类对象里。因此,如果有一个非静态内部类对象那么一定存在对应的外部对象,非静态内部类对象单独属于外部类的某个对象。
ⅱ非静态内部类可以使用外部类的成员,但是外部类不能直接访问非静态内部类成员。
ⅲ非静态内部类不能有静态方法、静态属性、静态初始化块。
ⅳ静态成员不能访问非静态成员:外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例。
ⅴ成员变量访问要点:
①内部类方法的局部变量:变量名
②内部类属性:this.变量名(不加也是this)
③外部类属性:外部类名.this.变量名(外部类属性和内部类属性重名的情况下)
ⅵ内部类的访问:
①外部类中定义内部类:newInnerClass()
②外部类以外的地方使用非静态内部类:
Outer.inner varname = OuterObject.newInner()
Face.Nose nose = new Face().new Nose();
Face f2 = new Face();
Face.Nose nose2 = f2.new Nose();
b)静态内部类
ⅰ定义方式:
static class Classname{
//类体
}
ⅱ使用要点:
①当一个静态内部类对象存在,并不一定在对应的外部类对象。因此,静态内部
类的实例方法不能直接访问外部类的实例方法。
②静态内部类看做外部类的一个静态成员。因此,外部类的方法中可以通过:
静态内部类.名字访问静态内部类的静态成员。通过new静态内部类()访问静态内部类的实例。
③在外部类的外面创建静态内部类:
Face.TestStaticInner aInner = new Face.TestStaticInner();
2.匿名内部类
适合那种只需要使用一次的类。比如:键盘监听操作等等。语法:
new 父类构造器(实参类表)实现接口(){
//匿名内部类类体!
}
this.addWindowListener(new WindowAdapter(){
@Override
Public void windowClosing(WindowEvent e){
System.exit(0);
}
})
this.addKeyListener(new KeyAdapter(){
@Override
Public void keyPressed(KeyEvent e){
// TODO Auto-generated method stub
myTank.keyPressed(e);
}
@Override
public void keyReleased(KeyEvent e){
// TODO Auto-generated method stub
myTank.keyPressed(e);
}
});
局部内部类
定义在方法内部。作用域只限于本方法。用的非常少。
递归结构
递归是一种常用的解决问题的方法,即把问题逐渐简单化。递归的基本思想就是“自己调用自己”,一个使用递归技术的方法将会直接或者间接的调用自己。
递归结构包括两个部分:
定义递归头。解答:什么时候不调用自身方法。如果没有头,将陷入死循环。
递归体。解答:什么时候需要调用自身方法。
API文档的阅读
API是什么?
——Application Programming Interface应用程序编程接口
Package的简单使用
——java中的核心包:java.lang包
生成自己项目的API文档
特殊的注释:
——文档注释:/**
使用javadoc生成API文档
——解决问题:代码和文档的分离
常用的java注释标签:
@Author 作者
@version 版本
@param 参数
@return 返回值的含义
@throws 抛出异常描述
@deprecated 废弃。用户不再使用该方法。
Package包的用法
为什么需要package?
——为了解决类之间的重名问题。
——为了便于管理类:合适的类位于合适的包!
package怎么用?
——通常是类的第一句非注释性语句。
——包名:域名倒着写即可,再加上模块名,并与内部管理类。
注意事项:
写项目时都要加包,不要使用默认包。
com.gao和com.gao.car,这两个包没有包含关系,是两个完全独立的包。只是逻辑上看起来后者是前者的一部分。
用途:
将功能相近的类放在同一个包中,可以方便查找与使用。
‚由于在不同包中可以存在同名类,所以使用包在一定程度上可以避免命名冲突。
ƒ在Java中,某次访问权限是以包为单位的。
创建包:
创建包可以通过在类或接口的源文件中使用package语句实现,package语句通常位于类或接口源文件的第一行,package语句的语法格式如下:
package 包名;
或package 包名1.包名2...包名n;//包1为最外层的包,而包n则为最内层的包。
如何编译带包名的类?
1.当源文件和指定的包在同一目录,使用以下命令进行编译:
javac 文件名.java
2.当源文件和指定的包不在同一目录,使用以下命令进行编译:
javac 路径/文件名.java
javac ../路径/文件名.java
如何运行带包名的类?
运行带包名的类和不带包名的类是有区别的,运行带包名的类必须加上包名如:
java 包名.java文件名
Import
import语句应该出现在package语句(如果有的话)之后、类定义之前。
一个java源文件只能包含一个package语句,但可以包含多个import语句,多个import语句用于导入多个层次下的类。
使用import语句导入单个类的用法如下:
import packageName.ClassName;
使用import语句导入指定包下全部类的用法如下:
import packageName.*; //*号只能代表类,不能代表包。
使用import语句导某个类的一个静态方法用法如下:
import staticpackageName.ClassName.methodName();
如何访问带包名的类
1.如果在同一个包下可以自由访问;
2.如果不在同一个包下则需要带上包名如:
java.util.Scanner sc = new java.util.Scanner(System.in)
3.使用import导入包,直接用类名.属性(方法名)访问。
垃圾回收机制(Garbage Collection)B
对象空间的分配
使用new关键字创建对象即可
对象空间的释放
将对象赋值null即可。垃圾回收器将负责回收所有“不可达”对象的内在空间。
要点:
①程序员无权调用垃圾回收器。
②程序员可以通过System.gc()。通知GC运行,但是JAVA规范并不能保证立刻运行。
③finalize方法,是JAVA提供给程序员释放对象或资源的方法,但尽量少用。
面向对象的三大特征A
继承、封装(隐藏)、多态
——为了适应需求的多种变化,使代码变得更加通用!
继承(1)A
类是对对象的抽象,继承是对某一批类的抽象,从而实现对现实世界更好的建模。
提高代码的复用性!
extends的意思是“扩展”。子类是父类的扩展。
继承(2)A
继承(4)A
小结:
子类继承父类,可以得到父类的全部属性和方法(除了父类的构造方法和初始化块)。
Java中的类只有单继承,没有像C++那样的多继承。多继承会引起混乱,使得继承链过于复杂,系统难于维护。就像我们现实中,如果你有多个父母亲,那是一个多么混乱的世界啊。多继承,就是为了实现代码的利用性,却引入了复杂性,使得系统类之间的关系混乱。
Java中类的多继承,可以通过接口来实现。
如果定义一个类时,没有调用extends,则它的父类是:java.lang.object。
不同的叫法:超类、父类、基类、子类、派生类。
Java中只有单继承——一个类只能有一个直接父类,但可以有无数个间接父类。
方法重写(override)
方法重写需要遵循哪些规则:
1.方法名相同
2.方法的形参列表相同
3.子类方法返回值类型应比父类方法返回值类型更小或者相等(指的是子类实例比父类实例小)
4.子类方法中声明抛出的异常类应比父类方法中声明抛出的异常类更小或相等(异常介绍)
5.子类方法的访问权限应比父类方法的访问权限更大或相等。
* 总结一句话:两同两小一大一注意。
注意:覆盖方法和被覆盖方法要么都是类方法,要么都是实例方法,不能一个是实例方法,一个类方法。
什么是方法重写:
在一个子类包含与父类同名方法的现象被称为方法重写,也被称为方法覆盖(Override)。
为什么方法重写:
当父类方法无法满足子类的功能的时候,子类就要重写父类的方法。
Object类A
Object类是所有Java类的根基类。
如果在类的声明中未使用extends关键字指明基类,则默认基类为Object类
this
普通方法中,this总是指向调用该方法的对象。
构造方法中,this总是指向正要初始化的对象。
this不能用于static方法。
super关键字A
super是直接父类对象的引用。可以通过super来访问父类中被子类覆盖的方法或属性。
普通方法:
没有顺序限制。可以随便调用。
构造函数中
任何类的构造函数中,解码器是构造函数的第一行代码没有显式的调用super(..);那么Java默认都会调用super();作为父类的初始化函数。所以你这里的super();加不加都无所谓。
静态方法中不能使用super关键字【static】
super和this的区别
1).super(参数):调用父类的构造方法(而这个超类指的是离自己最近的一个父类)。
2).this(参数):调用本类的其他构造方法。
都必须放在构造方法的第一行。
3). super:引用父类中的成员,当子类和父类中的方法重名时,这样用。
4). this:代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)。
5).this和super均不能在static环境中使用。包括:static变量,static方法,static语句块。
6).从本质上讲,this是一个指向本对象的指针,然
而super是一个Java关键字。
父类、子类中成员执行顺序
输出结果:
父类--静态变量
父类--静态初始化块
子类--静态变量
子类--静态初始化块
*************in main***************
父类--变量
父类--初始化块
父类--构造器
子类--变量
子类--初始化块
子类--构造器
final关键字A
修饰变量:常量
修饰方法:该方法不可被重写。但是可以被重载!
修饰类:修饰的类不能有了类,不能被继承。比如:Math.String。
抽象类A
为什么需要抽象类?如何定义抽象类?
①是一种模版模式。抽类为所有子类提供了一个通用模版,子类可以在这个模版基础上进行扩展。
②通过抽象类,可以避免子类设计的随意性。通过抽象类我们就可以做到严格限制子类的设计,使子类之间更加通用。
要求:
√有抽象方法的类只能定义抽象类。
√抽象类不能实例化,及不能用new来实例化抽象类。
√抽象类可以包含属性、方法、构造方法、初始化块。但是构造方法不能用来new实例,只能用来被子类调用。
√抽象类只能用来继承。
√抽象方法必须被子类实现。
抽象类语法
[权限修饰符] abstract返回值 方法(形参);
注意:
1.该方法是没有方法体,所有的抽象方法是无法完成业务功能,所以让子类重写该方法。抽象方法是定义在抽象类中或者接口中(定义方法的行为)。
2.重写父类的抽象方法也遵守方法重写的原则。
抽象类的成员
抽象类中成员包含:抽象方法、初始化块、方法、成员变量、内部类、构造器。
成员介绍:
抽象方法:该方法是没有方法体,但是必须要使用abstract关键修饰方法,子类继承抽象类要重写该抽象类中所有抽象方法。
初始化块、内部类、方法、成员变量、构造器:之前学过,此处跳过
注意:此处讲的重点是抽象方法。
抽象类与普通类的区别
相同点:
可以定义方法、成员变量、初始化块、内部类、构造器。
都可以被子类继承。
不同点:
普通类可以实例,而抽象类不能实例
普通类中不能定义抽象方法。
普通类必须要重写父类中抽象方法,而抽象可以不用。
抽象类的方法在扩展性和延伸性方面要比普通类的好
接口interface A
为什么需要接口?接口和抽象类的区别?
接口就是比“抽象类”还“抽象”的“抽象类”,可以更加规范的对子类进行约束。全面地专业地实现了:规范和具体实现的分离。
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是…则必须能…”的思想,如果你是天使,则必须干掉坏人;如果你是坏人,则必须欺负好人。
接口的本质是契约,就像我们人的法律一样。制定好后大家都遵守。
项目的具体需求是多变的,我们必须以不变应万变才能从容开发,此处“不变”就是“规范”。因此,我们开发项目往往都是面向接口编程!
接口的语法:
接口通常以interface来声明,语法:
[权限修饰符] interface接口名{
//成员
}
例子:
public interface MyInterface{
}
接口的成员:
抽象方法:该方法同抽象类中抽象方法,但是在接口中,抽象方法可以不添加public、abstract关键字修饰方法(默认添加了public、abstract)。
抽象方法语法:
[public] [abstract] 返回值类型 方法名(形参列表);
常量:接口中常量都是static修饰的静态常量,但是在接口中,静态常量可以不添加public、final、static关键字修饰方法(默认添加了public、final、static)。
常量语法:
[public] [static] [final] 数据类型 变量名=常量值;
在Java中除八大基本类型以外,其他的都是引用类型。
接口里只有常量和抽象方法
实现接口:
当类实现接口的时候,类要实现接口中所有的
抽象方法。否则,类必须声明为抽象的类。类使用implements关键字实现接口。在类声明中,implements关键字放在class声明后面。
实现一个接口的语法:
public class 类 implements接口1,接口2, ...{
//重写接口中方法
}
实现接口的原则
在实现接口的时候,也要注意一些规则:
一个类可以同时实现多个接口(接口之间使用逗号隔开)。
一个类只能继承一个类,但是能实现多个接口。
实现多个接口的类,必须要重写所有的接口中的方法,除非是抽象类。
接口继承接口
一个接口能继承另一个接口,和类之间的继承方式比较相似。接口的继承使用extends关键字,子接口继承父接口的方法。
在Java中,类的多重继承是不合法,但接口允许多重继承。
在接口的多重继承中extends关键字只需要使用一次,在其后跟着继承其他的接口。 语法:
public interface 子接口 extends 父接口1,父接口2, ...{
//成员
}
接口的特性
接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键子。
接口中的方法和常量都是公有的(public)。
接口和类的相似点
相似点:
一个接口可以有多个方法。
一个接口中可以定义多个静态常量
接口文件保存在.java结尾的文件中,文件名使用接口名。
接口的字节码文件保存在.class结尾的文件中。
接口相应的字节码文件必须在与包名称相匹配的包结构中。
接口和类的区别
区别:
接口不能用于实例化对象。
接口没有构造方法。
接口没有初始化块。
接口中所有的方法必须是抽象方法。
接口不能包含成员变量,除了static和final变量。
接口不是被类继承了,而是要被类实现。
接口支持多重继承。
接口interface A
√子类通过implements来实现接口中的规范。
√接口不能创建实例,但是可用于声明引用量类型。
√一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是public的。
√接口支持多继承。
接口和抽象类的相同点和不同点
A.相同点
1.都有抽象方法,静态常量。
2.都是不能实例。
3.都可以不用重写父类(父接口)中的抽象方法。
B.不同点
1.抽象类只有单继承,而接口可以实现多继承。
2.抽象类是以abstract class声明,接口是interface声明。
3.抽象类比接口多了:初始化块、构造器、普通方法(包括静态方法)、成员变量。
4.抽象类被子类继承(extends),接口是被子类实现(implements)。
隐藏/封装(encapsulation)A
为什么需要封装?封装的作用和含义?
我要看电视,只需要按一下开关和换台就可以了。有必要了解电视机内部的结构吗?有必要碰碰显像管吗?
隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。
我们程序设计要追求“高内聚,低耦合”。
√高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;
√低耦合:公共暴露少量的方法给外部使用。
√提高了程序的可复用性和可维护性,降低了程序员保持数据与操作内容的负担。
√对象的数据封装特性还可以把对象的私有数据和公共数据分离开,保护了私有数据, 减少了可能的模块间干扰,达到降低程序复杂性、提高可控性的目的。
使用访问控制符,实现封装A
|
同一个类 |
同一个包中 |
子类 |
所有类 |
private |
√ |
|
|
|
default(默认) |
√ |
√ |
|
|
protected |
√ |
√ |
√ |
|
public |
√ |
√ |
√ |
√ |
封闭要点
类的属性的处理:
1.一般使用private(除非本属性确定会让子类继承)
2.提供相应的get/set方法来访问相关属性。这些方法通常是public,从而提供对属性的读取操作。(注意:boolean变量的get方法是用:is开关!)
一些只用于本类的辅助方法可以用private,
希望其他类调用的方法用public。
静态的属性和方法建议用public修饰。
getter、setter方法
public class Student {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id =id;
}
public String getName() {
return name;
}
public void setName(Stringname) {
if(name!=null){//提高修改属性的规范性
this.name =name;
}
}
}
以上实例中public方法是外部类访问该类成员变量的入口。
通常情况下,这些方法被称为getter和setter方法。
因此,任何要访问类中私有成员变量的类都要通过这些getter和setter方法。
public class Test {
public static void main(String[]args) {
Student stu = new Student();
stu.setId(10);
stu.setName("小黑");
}
}
多态polymorphism A
什么是多态
当把一个子类对象直接赋给父类引用变量时,例如:
SuperClass sc =new SubClass();
这个sc引用变量的编译时类型是SuperClass,而运行时类型是SubClass,当运行时调用该引用变量的方法时,其方法行为总是表现出子类方法的行为特征,而不是父类方法的行为特征,这可能出现:
相同类型的变量、调用同一个方法时呈现出多种不同的行为特征,这就是多态。
多态的存在要有3个必要条件:
要有继承,要有方法重写,父类引用指向子类对象。
使用多态的好处?
多态性是OOP中的一个重要特性,主要是用来实现动态联编的,换句话说,就是程序的最终状态只有在执行过程中才被决定而非在编译期间就决定了。这对于大型系统来说能提高系统的灵活性和扩展性。
Java中如何实现多态?
引用变量的两种类型:
编译时类型(模糊一点,一般是父亲)
由声明时的类型决定。
运行时类型(运行时,具体是哪个子类就是哪个子类)由实际对应的对象类型决定。
引用变量的强制类型转换
1.系统自动转换(向上转型)
因为子类其实是一种特殊的父类,因此java运行把一个子类对象直接赋给一个父类引用变量,无须任何类型转换,或者被称为向上转型(upcasting),向上转型由系统自动完成。
2.强制转换
编写java程序时,引用变量只能调用它编译时类型的方法,而不能调用它运行时类型的方法,即使它实际所引用的对象确实包含该方法。如果需要让这个引用变量调用它运行时类型的方法,则必须把它强制类型转换成运行时类型,强制类型转换需要借助于类型转换运算符。
(type)variable
注意:引用类型之间的转换只能在具有继承(实现)关系的两个类型之间进行,如果是两个没有任何继承关系的类型,则无法进行类型转换,否则编译时就会出现错误。(运行时引发ClassCastException异常:类型转换异常)
instanceof运算符
instanceof运算符的前一个操作数通常是一个引用类型变量,后一个操作数通常是一个类(也可是接口,可以把接口理解成一种特殊的类),它用于判断前面的对象是否是后面的类,或者其子类、实现类的实例。如果是,则返回true,否则返回false。
if(sc instanceof SubClass){
SubClass sub = (SubClass)sc;
}
在进行强制类型转换之前,首先判断前一个对象是否是后一个类的实例,是否可以成功转换,从而保证代码更加健壮。instanceof和(type)是java提供的两个相关的运算符,通常先用instanceof判断一个对象是否可以强制类型转换,然后再提供使用(type)运算符进行强制类型转换,从而保证程序不会出现错误。
基本数据类型的包装类A(Wrapper Class)
为什么需要包装类?
JAVA并不是纯面向对象的语言。Java语言是一个面向对象的语言,但是Java中的基本数据类型却是不面向对象的。但是我们在实际使用中经常需要将基本数据转化成对象,便于操作。比如:集合的操作中。这是,我们就需要将基本类型数据转化成对象!
包装类基于java.lang包,包装类和基本数据类型的对应关系:
基本数据类型 |
包装类 |
byte |
Byte |
boolean |
Boolean |
short |
Short |
char |
Character |
int |
Integer |
Long |
Long |
float |
Float |
double |
Double |
如何使用包装类?A
包装类的作用:
——提供:字符串、基本类型数据、对象之间互相转化的方式!
——包含每种基本数据类型的相关属性和最大值、最小值等
所有的包装类(Wrapper Class)都有类似的方法,掌握一个其他都类似!以Integer为例!
代码:TestWrapperClass1.java
Ferrari笔记
相关文章
- 暂无相关文章
用户点评