黑马程序员入学Java知识——精华总结
J2SE部分,Java高新技术部分,7K面试题部分等黑马入学要求的知识点总结!
9、代码注释:单行//,多行/* */,文档注释/** */ 9
7、 Singleton模式(单例模式) 饿汉式和懒汉式 44
11、StringBuffer 与 StringBuilder 69
3、文件过滤器 java.io.FilenameFilter 126
7、合并流(SequenceInputStream) 145
5、Class中得到构造方法Constructor、方法Method、字段Field 167
一、黑马程序员—java概述与基础知识
1、何为编程?
编程就是让计算机为解决某个问题而使用某种程序设计语言编写程序代码,并最终得到结果的过程。
为了使计算机能够理解人的意图,人类就必须要将需解决的问题的思路、方法、和手段通过计算机能够理解的形式告诉计算机,使得计算机能够根据人的指令一步一步去工作,完成某种特定的任务。这种人和计算机之间交流的过程就是编程。
2、Java语言概述,历史、特点
是SUN(Stanford University Network,斯坦福大学网络公司)1995年推出的一门高级语言。
是一种面向Internet的编程语言。
随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。
是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
java5.0之后的三大技术框架
J2EE(Java 2 Platform Enterprise Edition)企业版
在jdk5.0版本后称为JAVAEE,是为开发企业环境下的应用程序提供的一套解决方案。该技术体系中包含的技术如Servlet Jsp等,主要针对于Web应用程序开发。是传智播客就业班和黑马训练营的主要学习内容之一.。
J2SE(Java 2 Platform Standard Edition)标准版
在jdk5.0版本后称为JAVASE,这是在java基础阶段主要学习的内容,也是java的基础,以后不管从事Android开发或者是物联网+云计算的开发,等是建立在JSE基础上的,因此该技术是java的最核心技术,是传智播客基础班的主要上课内容.。
J2ME(Java 2 Platform Micro Edition)小型版
在jdk5.0版本以后称为JAVAME,该技术多应用于一些电子产品的嵌入式开发,以前在手机开发上应用的也比较多,但是随着智能手机的发展,现在手机应用程序(比如Android程序)的开发已经不再使用该技术。
3、什么是跨平台性?原理是什么?JVM
所谓跨平台性,是指java语言编写的程序,一次编译后,可以在多个系统平台上运行。
实现原理:Java程序是通过java虚拟机在系统平台上运行的,只要该系统可以安装相应的java虚拟机,该系统就可以运行java程序。(注意不是能在所有的平台上运行,关键是该平台是否能安装相应的虚拟机)。
我的总结:Java程序之所以能够实现跨平台运行,是因为它根本就不直接运行在任何底层平台上,而是需要在哪里运行,就在哪里(如Windows平台)事先准备好自己的Java平台,而这只是仅仅是安装和配置一个软件而已!
4、Jre和Jdk的区别?
JRE:(Java Runtime Environment),java运行环境。包括Java虚拟机(JVM Java Virtual Machine)和Java程序所需的核心类库等,如果想要运行一个开发好的Java程序,计算机中只需要安装JRE 即可。
JDK:(Java Development Kit Java)开发工具包。JDK是提供给Java开发人员使用的,其中包含了java的开发工具,也包括了JRE。所以安装了JDK,就不用在单独安装JRE了。
其中的开发工具:编译工具(javac.exe) 打包工具(jar.exe)等
简单而言:使用JDK开发完成的java程序,交给JRE去运行。
我的总结:必须熟练的记忆,核心类库,开发工具!
5、java虚拟机JVM
Java Virtual Machine ,简称JVM;
它是运行所有Java程序的抽象计算机,是Java语言的运行环境,它是Java 最具吸引力的特性之一,JVM读取并处理编译过的与平台无关的字节码(class)文件。
Java编译器针对JVM产生class文件,因此是独立于平台的。
Java解释器负责将JVM的代码在特定的平台上运行。
Java虚拟机是不跨平台的.
6、Java程序运行机制
编译: javac 文件名.文件后缀名
运行: java 类名
我的总结:Java程序的组成:Java源文件,字节码文件。
7、学习java注意的地方
Java语言拼写上严格区分大小写;
一个Java源文件里可以定义多个Java类,但其中最多只能有一个类被定义成public类;
若源文件中包括了public类,源文件必须和该public类同名;
一个源文件中包含N个Java类时,编译后会生成N份字节码文件,即每个类都会生成一份单独的class文件,且字节码文件名和
其对应的类名相同;
我的总结:一个Java源文件只定义一个类,不同的类使用不同的源文件定义;
将每个源文件中单独定义的类都定义成public的;
保持Java源文件的主文件名与源文件中的类名一致;
8、Java语法格式
任何一种语言都有自己的语法规则,Java也一样,既然是规则,那么知道其如何使用就可以了。
代码都定义在类中,类由class来定义,区分 public class 和 class;
代码严格区分大小写,如main 和 Main 是不一样的;
Java中的标识符与关键字;
注释;
main方法的作用:
程序的入口
保证程序的独立运行
被JVM调用
9、代码注释:单行//,多行/* */,文档注释/** */
1.单行注释 //:
//后到本行结束的所有字符会被编译器忽略;
2.多行注释 /* */:
/* */之间的所有字符会被编译器忽略
3.文档注释 /** */:
在/** */之间的所有字符会被编译器忽略,java特有的(用于生成文档);
我的总结:多行和文档注释都不能嵌套使用。
10、Java中的标识符
可简单理解为在Java程序中为了增强阅读性自定义的名称。比如:类名,方法名,变量名等。
命名规则:
(1) 由字母、数字、下划线、$组成,不能以数字开头
注意:此处的字母还可以是中文,日文等;
(2) 大小写敏感
(3) 不得使用java中的关键字和保留字
(4) 别用Java API里面的类名作为自己的类名。
11、java中的常量和变量
变量的概念:
占据着内存中的某一个存储区域;
该区域有自己的名称(变量名)和类型(数据类型);
该区域的数据可以在同一类型范围内不断变化;
为什么要定义变量:
用来不断的存放同一类型的常量,并可以重复使用;
使用变量注意:
变量的作用范围, 初始化值
定义变量的格式:
数据类型 变量名 = 初始化值;
注:格式是固定的,记住格式,以不变应万变。
作用范围:定义开始到定义它的代码块结束;
同一范围内,不允许多个个局部变量命名冲突
12、Java成员变量和局部变量
局部变量:不是声明在类体括号里面的变量;
局部变量使用前必须初始化值;
局部变量没有默认初始化值;
局部变量的作用域是从定义开始到定义它的代码块结束;
成员变量:在方法体外,类体内声明的变量,又称字段(Field)或全局变量;(其实Java中没有全局变量,由于Java是面向对象语言,所有变量都是类成员)
成员变量的作用域是整个类中;
我的总结:注意成员变量和局部变量的区别
package reviewDemo;
public class Demo2 {
public static void main(String[] args) {
int i;
System.out.println(i);
}
}
备注:局部变量调用前没有初始化,所以编译的时候就会报错!
package reviewDemo;
public class Demo2 {
static int i;
public static void main(String[] args) {
System.out.println(i);
}
}
备注:此时i为全局变量,未初始化会被赋予默认的初始化值!程序正确!
我的总结:
局部变量是定义在方法中的变量,,,出了该方法就不能访问该变量了....
成员变量是在类中定义,,,,并且在类的成员方法中都能访问的变量..
13、基本数据类型
在数据类型中,最常用也是最基础的数据类型,被称作基本数据类型。可以使用这些类型的值来代表一些简单的状态。
Java 语言的基本数据类型总共有以下8 种,下面是按照用途划分出的4 个类别:
定点类型:
整数型是一类代表整数值的类型。当需要代表一个整数的值时,可以根据需要从4 种类型中挑选合适的,如果没有特殊要求的话,一般选择int 类型。4 种整数型区别主要在每个数据在内存中占用的空间大小和代表的数值的范围。
浮点类型:
小数型是一类代表小数值的类型。当需要代表一个小数的值时,可以根据需要从以下2 种类型中挑选合适的。如果没有特殊要求,一般选择double类型。
由于小数的存储方式和整数不同,所以小数都有一定的精度,所以在计算机中运算时不够精确。根据精度和存储区间的不同,设计了两种小数类型。
字符型:
字符型代表特定的某个字符,按照前面介绍的知识,计算机中都是以字符集的形式来保存字符的,所以字符型的值实际只是字符集中的编号,而不是实际代表的字符,由计算机完成从编号转换成对应字符的工作。Java 语言中为了更加方便国际化,使用Unicode 字符集作为默认的字符集,该字符集包含各种语言中常见的字符。在程序代码中,字符使用一对单引号加上需要表达的字符来标识,例
如’A’、’a’等,当然也可以直接使用字符编码,也就是一个非负整数进行表示。
布尔型:
布尔型代表逻辑中的成立和不成立。Java 语言中使用关键字true 代表成立,false 代表不成立。布尔型是存储逻辑值的类型,其实很多程序中都有逻辑值的概念,Java 把逻辑的值用布尔型来进行表达。
14、基本数据类型转换之向上转型和向下转换
向上转换:
整型,字符型,浮点型的数据在混合运算中相互转换,转换时遵循以下原则:
容量小的类型可自动转换为容量大的数据类型;
byte,short,char → int → long → float → double
byte,short,char之间不会相互转换,他们在计算时首先会转换为int类型。
boolean 类型是不可以转换为其他基本数据类型。
Eg:
int i = 123;
long l = i; //自动转换,不需强转
float f = 3.14F;
double d = f;
向下转换:
整型,字符型,浮点型的数据在混合运算中相互转换,转换时遵循以下原则:
容量小的类型可自动转换为容量大的数据类型;
byte,short,char → int → long → float → double
byte,short,char之间不会相互转换,他们在计算时首先会转换为int类型。
boolean 类型是不可以转换为其他基本数据类型。
Eg:
long l = 123L;
int i = (int) l;//必须强转
double d = 3.14;
float f = (float) d;
我的总结:类型转化
小转大,自动!自动类型转换(也叫隐式类型转换)
大转小,强转!强制类型转换(也叫显式类型转换)
15、Java的运算符
运算符是一种特殊符号,用以表示数据的运算、赋值和比较等共分以下几种:
算术运算符(+ 、— 、* 、/ 、%)
赋值运算符(= 、+=、-=、*=、/=,、%=)
关系运算符(>、>=、<、<=、!=)
条件运算符(&&、||、!&、|、^)
位运算符(&、|、^、~、>>、<<、<<<、>>>)
我的总结:
逻辑运算符用于连接布尔型表达式,在Java中不可以写成3<x<6,应该写成x>3 & x<6 。
“&”和“&&”的区别:单与时,左边无论真假,右边都进行运算;双与时,如果左边为真,右边参与运算,如果左边为假,那么右边不参与运算。
“|”和“||”的区别同理,双或时,左边为真,右边不参与运算。
“ ^ ”与“|”不同之处是:当左右都为true时,"^"结果为false。
16、表达式和三目运算符
是由数字、运算符、数字分组符号(括号)等以能求得数值的有意义排列的序列;
a + b
3.14 + a
(x + y) * z + 100
boolean b= i < 10 && (i%10 != 0)
表达式的类型和值:
对表达式中操作数进行运算得到的结果是表达式的值。
表达式值的数据类型即为表达式的类型。
表达式的运算顺序
应按照运算符的优先级从高到低的顺序进行;
优先级相同的运算符按照事先约定的结合方向进行;
“三目运算符”,语法格式:
x ? y : z;
其中x为boolean类型表达式,先计算x的值,若为true,则整个三目运算符的结果是表达式y的值,否则就是z的值。
package reviewDemo;
public class Demo2 {
public static void main(String[] args) {
String s = "lz";
s = (s == "lz" ? "正确" : "错误");
System.out.println(s);
}
}
输出:正确
17、程序流程控制
顺序结构
分支结构(条件结构)
循环结构
控制循环结构
顺序结构:
如果代码里没有流程控制,程序是至上而下一行一行执行的,一条语句执行完之后继续执行下一条语句,直到程序的最后。
if语句:
基本语法:if(表达式){ 方法体}else if(表达式){ 方法体}else(方法体)
几种形式:
三种格式:
if(条件表达式){ 执行语句;}
if(条件表达式){ 执行语句;}else{ 执行语句;}
if(条件表达式){ 执行语句;}else if (条件表达式){ 执行语句;}……else{ 执行语句;}
public class If3
{
public static void main(String args[])
{
int i = 3;
if (i > 5)
{
System.out.println("变量i大于5");
}
else if (i > 4)
{
System.out.println("变量i小于4");
}
else
{
System.out.println("其他");
}
}
}
switch控制语句
格式:
switch(表达式)
{
case 表达式可能的结果值1:
执行语句;
break;
case 表达式可能的结果值2:
执行语句;
break;
...
default:
执行语句;
break;//最后这个一般不写
}
备注:
case之间与default没有顺序。先执行第一个case,都没有匹配的case值执行default。
结束switch语句的两种情况:遇到break,switch语句执行结束。
如果匹配的case或者default没有对应的break,那么程序会从第一次匹配的case语句开始继续向下执行,运行可以执行的语句,直到遇到break或者switch结束为止。
class switch2
{
public static void main(String[] args)
{
int a = 7,b = 5;
switch(a-b)
{
case 3://表达式可能的值;
{
System.out.println("33!");
}
break;
case 4:
{
System.out.println("44!");
}
break;
default://都没有执行则 执行该语句!
System.out.println("其它的");
}
}
}
注意:switch语句只能使用byte、char、short、int四种基本类型以及它们的包装类和枚举
18、三大循环结构:
用于处理需要重复执行的操作;
根据判断条件的成立与否,决定程序段落的执行次数,而这个程序段落我们称为循环体;
while:事先不需要知道循环执行多少次;
do while:同上,只是至少要执行一次(先做,后判断);
for:需要知道循环次数;
循环结构(while & do while)
while语句
格式:
while(条件表达式值为true)
{
执行语句;
}
do while语句
格式:
do
{
执行语句;
}
while(条件表达式值为true);
我的总结:do while特点是无论条件是否满足,循环体至少被执行一次。
循环里的条件表达式不能直接写false或直接写结果是false的表达式,不过可以使用变量来传递false值;
循环结构(for)
格式:
for(初始化表达式(1);循环条件表达式(2);循环后的操作表达式(3))
{
执行语句;(4)
}
执行顺序:(1) → (2) → (4) → (3) → (2) → (4) → (3)
备注:
1, for里面的3个表达式运行的顺序,初始化表达式只读一次,判断循环条件,为真就执行循环体,然后再执行循环后的操作表达式,接着继续判断循环条件,重复找个过程,直到条件不满足为止。
2, while与for可以互换,区别在于for为了循环而定义的变量在for循环结束就在内存中释放。而while循环使用的变量在循环结束后还可以继续使用。
3, 最简单无限循环格式:while(true) , for(;;),无限循环存在的原因是并不知道循环多少次,而是根据某些条件,来控制循环。
Eg:
用三种循环控制求出100以内前5个3的倍数的数字;
class while
{
public static void main(String[] args)
{
int i = 1,k = 0;
while(i<=100)
{
if(i%3==0)
{
if(k<5)
System.out.println(i);
k++;
}
i++;
}
}
}
class dowhile
{
public static void main(String[] args)
{
int i = 1,k = 0;
do{
if(i%3==0)
{
if(k<5)
System.out.println(i);
k++;
}
i++;
}
while(i<=100);
}
}
class for
{
public static void main(String[] args)
{
int i = 1,k = 0;
for(;i<100;i++)
{
if(i%3==0&&k<5)
{
System.out.println(i);
k++;
}
}
}
}
19、嵌套循环与流程控制
嵌套循环:循环里套循环
假设外循环的循环次数是m次,内循环的循环次数是n次,那么内层循环的循环次数需要 m * n次。
Eg:利用for循环语句的嵌套打印出乘法口诀表
class break1
{
public static void main(String[] args)
{
for(int i=1;i<=10;i++)//定义i与j的值必须在for循环里面,否则每次跳出循环重新执行就无法取值
{
for(int j=1;j<=10;j++)
{
if(j<=i)
System.out.print(j+"*"+i+"="+i*j+" ");//小注意:print()括号里面
必须传递参数,println()无限制!
}
System.out.println();
}
}
}
流程控制
break语句、 continue语句;
break:终止该层循环;
continue:跳过该层循环
注:
①:若这两个语句离开应用范围,存在是没有意义的。
②:这个两个语句后面都不能有语句,因为执行不到。
③:continue语句是跳过本次循环,继续下次循环。
④:标签的出现,可以让这两个语句作用于指定的循环。
Eg:
package reviewDemo;
public class Demo2 {
public static void main(String[] args) {
int i = 1;
for (; i < 10; i++) {
System.out.println(i);
if(i == 8){
break;//流程控制,不会完全执行!
}
}
}
}
二、黑马程序员—方法与数组
第二篇:
1、什么是方法(Method)?
方法是一组为了实现特定功能的代码块的集合。方法在语法上的功能主要有以下两个:
①:结构化代码
将代码按照功能进行组织,使代码的结构比较清晰,容易阅读和修改,也就是程序的可维护性强。
②:减少代码重复
一个固定的功能,可能会在程序中多次使用,在使用时只需要调用写好的方法,而不用重复书写对应的功能代码。
方法在书写时需要注意以下两点:
①:逻辑严谨
方法实现的一个完整的功能,所以在书写时要考虑到各种可能的情况,并对每种情况做出恰当的处理。
②:通用性强(可重复利用)
方法实现的是一种功能,在实际实现时,可以根据需要,使方法具备一定的通用性,除非必要,否则不要写专用的方法。在Java 语言中,恰当的使用方法,将使程序更加优雅,便于阅读和使用。
我的总结:
方法:一段可重复使用的代码段;
程序中完成独立功能的一段代码的集合。
2、Java中方法的格式:
[修饰符] 返回值类型 方法名([参数类型 形式参数1,参数类型 形式参数2,……])
{
执行语句; [return 返回值;]//需要的话
}
参数列表(参数的类型 ,参数的个数,参数的顺序)
我的总结:只要上述有一个不一样,那么这个参数列表就不一样!对于方法而言,即使同名也不是同一个方法,也就是下面讲的方法签名。
3、方法里的属性
访问控制符:访问控制符限定方法的可见范围,或者说是方法被调用的范围。方法的访问控制符有四种,按可见范围从大到小依次是:public、protected,无访问控制符,private。其中无访问控制符不书写关键字即可。具体的范围在后续有详细介绍。
形式参数:在方法被调用时用于接收外界输入的数据。
实参:调用方法时实际传给方法的数据。
返回值:方法在执行完毕后返还给调用它的环境的数据。
返回值类型:事先约定的返回值的数据类型,如无返回值,必须给出返回类型 void。
方法签名:方法名和方法的参数列表(能区别方法);//最关键的
java语言中调用方法:对象名.方法名(实参列表)。
实参的数目、数据类型和次序必须和所调用方法声明的形参列表匹配。
return 语句终止方法的运行并指定要返回的数据。
4、方法特点
它可以实现独立的功能;
必须定义在类里面;
它只有被调用才会执行;
它可以被重复使用;
方法结束后方法里的对象失去引用;
如何定义一个功能,并通过方法体现出来:
① 明确该功能运算后的结果.明确返回值类型;
② 明确在实现该功能过程中是否有未知内容参与运算,确定参数列表;
Eg:
package reviewDemo;
/**
* player 的值分别是1,2,3或者其他值时,该方法返回“大明”,“二明”,“小明”,“我没有这个孩子”。
*/
public class Demo2 {
public static void main(String[] args) {
int player = 5;
System.out.println("返回的结果是:"+show(player));
}
public static String show(int p){
switch (p) {
case 1:
return "大明";
case 2:
return "二明";
case 3:
return "小明";
default:
return "我没有这个孩子!";
}
}
}
5、什么是方法的重载(Overload)?
概念:
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型或参数顺序不同即可。
存在的原因:
屏蔽了一个对象的同一类方法由于参数不同所造成的差异。
特点:
与返回值类型无关,只看参数列表。
以下是方法重载的示例:
public void a(int a){}
public int a(){}
public void a(int a,String s){}
Eg:
class Chongzai
{
public static void main(String[] args)
{
int ret = name(3,4,5);
System.out.println(ret);
}
public static int name(int a, int b)
{
int c = a+b;
return c;
}
public static int name(int a, int b, int m)//这就叫做方法的重载,只要参数列表不一样。好处:用户使用时限制很小;
{
int c = a+b+m;
return c;
}
}
我的总结:方法重载,方法名相同,但是参数列表不一致!(和方法覆写不一样,方法覆写的方法名和参数列表都必须一样),注意方法重载和方法覆写的不同!
6、可变参数
从java5开始出现了可变参数,这是对java方法及数组的拓展!
方法中可以接受的参数不再是固定个数的,而是随着具体需求传递的多少来决定。
定义格式: 返回值类型 方法名(参数类型 ... 形式参数){ }
可变参数的特点:
只能出现在参数列表的最后;
... 位于变量类型和变量名之间,前后有无空格都可以;
调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。
Eg:
package reviewDemo;
import java.util.Arrays;
public class Demo6 {
public static void main(String[] args) {
int []age = {1,2,3,69,36,636,459};
show(age);
}
public static void show(int...a){ //此时这里写的就是可变参数,和数组的作用一样!
//把数组给打印出来!
System.out.println(Arrays.toString(a));
}
}
7、数组简介:
数组(Array)是Java 语言中内置的一种基本数据存储结构,通俗的理解,就是一组数的集合,目的是用来一次存储多个数据。数组是程序中实现很多算法的基础,可以在一定程度上简化代码的书写。
备注:
1. 数组的好处:数组里的每个元素都有编号,编号从0开始,并且依次递增,方便操作这些元素;
2. 使用Java数组:必须先声明数组,再给该数组分配内存;
3. 数组对应在内存中一段连续空间。
4. 数组元素必须是相同数据类型,也可以是引用数据类型,但是同一个数组中的元素必须是同一类数据类型。
8、一维数组的声明与初始化:
一维数组:可以理解为一列多行、类型相同的数据,其中每个数据被称为数组元素;
一维数组的声明方式:
type varName[]; 或 type[] varName;(推荐)
Eg:int age[]; int []age;
数组的长度一旦确定,就不能改变,也就数组是定长的;
我的总结:java语言声明数组的时候不能指定其长度(元素的个数)
Eg:int a[5]; //非法
初始化:
Java中的数组必先初始化才可以使用,所谓初始化就是为数组的数组元素分配内存,并为每个数组元素赋值;
数组初始化的两种方式:
静态初始化:初始化时由我们自己指定每个数组元素的初始值,由系统决定需要的数组长度;
格式:数组名 = new 数组类型[]{ 元素1,元素2,元素3...元素n};
简化语法:数组名 = { 元素1,元素2,元素3...元素n};
动态初始化:初始化时由我们指定数组的长度,由系统为数组元素分配初始值;
格式:数组名 = new 数组类型[数组长度];
我的总结:
不能静态和动态初始化同时使用:
也就是说不能同时指定数组的长度和元素;
Eg:
/**
* 声明数组及初始化
*/
public class Demo3 {
public static void main(String[] args) {
int []age = new int[10];
//动态初始化
for (int i = 0; i < age.length; i++) {
age[i] = i;
System.out.print(age[i]+" ");
}
}
}
输出:0 1 2 3 4 5 6 7 8 9
9、数组的使用:
Java语言的数组索引是从0开始的,也就是说数组里的第一个元素的索引是0,第二个元素的索引是1,依次可以类推。
常见操作:
给数组元素赋值
数组名[索引] = 数组类型的值 ;
访问数组元素
数组类型 变量 = 数组名[索引];
得到数组的长度
int len = 数组名.length; //length是数组的属性
遍历数组(备注:length 属性和循环语句)
数组元素的索引范围(0,长度—1)
Eg:判断数组是否重复
package reviewDemo;
/**
* 判断数组是否重复
*/
public class Demo3 {
public static void main(String[] args) {
int []age = {1,2,3,4,5,6,5};
for (int i = 0; i < age.length-1; i++) { //双层循环,定住一个,再考虑下一个!
for (int j = i+1; j < age.length; j++) {
if(age[i] == age[j]){
System.out.println("有重复的!"+i+" "+j);
break;
}
}
}
}
}
求最大值:
package reviewDemo;
public class Demo4 {
public static void main(String[] args) {
int age[] = new int[] { 12, 26, 3, 60, 55, 6, 48, 4, 98 };
int max = age[0];
for (int i = 0; i < age.length; i++) {
if (max < age[i]) {
max = age[i];
}
}
System.out.println(max);
}
}
经典用法:冒泡法排序
class Bubblesort
{
public static void main(String args[])
{
int [] arr={5,1,6,4,2,8,9};
bubble(arr);
printarray(arr);
}
public static void bubble(int[] arr)
{
for (int i=0;i<arr.length-1 ;i++ )
{
for (int y=0;y<arr.length-i-1 ; y++) //让每一次比较的元素减少,-1是为了防止数组角标越界;
{
if(arr[y]>arr[y+1]) //相邻两元素相比
{
int temp = 0;
temp = arr[y];
arr[y] = arr[y+1] ;
arr[y+1] = temp;
}
}
}
}
public static void printarray(int[] arr)
{
for (int i=0;i<arr.length ;i++ )
{
if(i!=arr.length-1)
System.out.print(arr[i]+",");
else
System.out.println(arr[i]);
}
}
}
//选择排序
public class Demo6 {
public static void main(String[] args) {
int []age = {1,2,36,363,56,95,12,32,1232,3263};
for (int i = 0; i < age.length; i++) {
for (int j = i+1; j <= age.length-1; j++) {
if(age[i] > age[j]){
int temp = age[i];
age[i] = age[j];
age[j] = temp;
}
}
}
System.out.println(Arrays.toString(age));
}
}
//输出为:[1, 2, 12, 32, 36, 56, 95, 363, 1232, 3263]
10、分配内存空间
分配内存空间
数组名=new 数据类型[数组长度];
new关键字用来实现为数组或对象分配内存 (堆内存)
数组具有固定的长度。获取数组的长度: 数组名.length
定义数组+分配内存空间
数据类型[]数组名=new 数据类型[数组长度];
定义数组时不指定长度,分配空间时指定数组长度;如:String cities[] = new String[6];
数组元素:
数组名[下标值];
数组下标从0开始 scores[0]=75;
数组的内存分配 栈内存和堆内存
如定义一个数组 int[]scores将在栈内存中为scores 分配内存空间,其值是一个不确定的值。
当执行语句scores=new int[5]时,将在堆内存分配连续5个空间,每个空间4个字节,用于存放整型数据,其初始值为0,然后将该段空间首地址,也就是第一个元素的地址,比如0*3000,赋给scores变量。该地址相当于一个指针,指向堆内存中分配的空间。此时堆内存中分配的5个空间可以分别使用scores[0],一直到scores[4]来表示。当执行四个赋值语句时,分别用指定值填充到对应元素位置。如果此时将null值赋给scores时,scores变量将不再指向任何位置,此时堆内存中分配的空间就变成了垃圾,由垃圾回收器在某一时间进行回收。
在方法中定义的变量,包括基本数据类型变量和引用数据类型变量,都将在栈内存中分配空间,当超过变量作用范围后,自动回收
我的总结:初始化=定义数组+分配空间+赋值
11、二维数组:
二维数组:(其实是一个一维数组,它的每一个元素又是一个一维数组),
可以看做是一张表格。
初始化:
动态初始化
int[ ][ ] arr = new int[3][2];
定义了一个二维数组,其中有3个一维数组,每一个一维数组中有2个元素
静态初始化
int[ ][ ] arr = new int[][]{ {1,2},{3,4},{5,6}};
int[ ][ ] arr = { {1,2},{3,4},{5,6}};
Eg:
public class Demo3 {
public static void main(String[] args) {
int age[][] = new int[][]{ {1,2},{3,4},{5,6,7}};
System.out.println(age[0].length);//2
System.out.println(age[2].length);//3
}
}
12、操作数组的工具类-Arrays
static int binarySearch(type[] a, type key) 使用二分搜索法来搜索key元素在数组中的索引;若a数组不包括key,返回负数。(该方法必须已按升序排列后调用)。
static int binarySearch(type[] a, int fromIndex, int toIndex, type key) 使用二分搜索法来搜索key元素在数组中从fromIndex到toIndex的索引;若a数组不包括key,返回负数。(该方法必须已按升序排列后调用)。
static boolean[] copyOf(type[] original, int newLength) 复制指定的数组见下面备注
static byte[] copyOfRange(type[] original, int from, int to) 将数组的指定范围复制到一个新数组。
static boolean equals(type[] a, type[] a2) 如果两个数组长度相等和元素一一相等,则返回 true
static void fill(type[] a, type val) 将a数组所有元素都赋为val。
static void fill(type[] a, int fromIndex, int toIndex, type val) 将a数组从formIndex 到tiondex索引之间的元素都赋为val。
static void sort(type[] a) //sort(int[] arr)对指定的数组按数字升序进行排序。
static void sort(type[] a, int fromIndex, int toIndex) 对指定数组的从formIndex 到tiondex索引之间的元素按数字升序进行排序。
static String toString(type[] a) 返回指定数组内容的字符串表示形式。多个数组元素之间用英文逗号或空格隔开。
我的总结:使用数组工具类可以节省时间,提高效率,注意常查阅api;
Eg:
package reviewDemo;
import java.util.Arrays;
//使用Arrays类
public class Demo4 {
public static void main(String[] args) {
int[] age = new int[] { 12, 26, 3, 60, 55, 6, 48, 4, 98 };
System.out.println(Arrays.toString(age));//直接打印出数组的方法
int []age2 = {1,2,3,4,5,6,98,65,23};
int i = Arrays.binarySearch(age2, 98);
System.out.println(i);
}
}
13、Java5新特性对数组的支持:
增强for循环 → for-each
for (参数类型 参数名 : 数组名) {
代码块
}
Eg:
package reviewDemo;
public class Demo6 {
public static void main(String[] args) {
int []age = {1,2,3,69,36,636,459};
for (int i : age) {
System.out.println(i);
}
}
}
这样就用for-each把数组遍历输出!
我的总结:for-each用于数组和Iterable对象!在以后的集合学习中还会经常用到for-each循环。
三、黑马程序员—面向对象(1)
第三篇:
1、什么叫面向对象?
面向对象(Object-Oriented,简称OO)就是一种常见的程序结构设计方法。
面向对象思想的基础是将相关的数据和方法放在一起,组合成一种新的复合数据类型,然后使用新创建的复合数据类型作为项目的基础。
面向对象是一个很抽象的概念,它相对面向过程而言。
过程与对象都是一种解决问题的思想。
面向过程:强调的是功能行为,一种过程,先干啥,再干啥;
面向对象:将功能封装到对象里,强调的是具备某功能的对象;
按照面向对象的思想,可以把任何的东西看做对象!
面向对象的三个特征:
封装(Encapsulation);
继承(Inheritance);
多态(Polymorphism)。
我的总结:
面向过程:强调的是具体的功能实现;(执行者)
面向对象:强调的是具备功能的对象。(管理者)
2、类
类(class)是Java 语言的最小编程单位,也是设计和实现Java 程序的基础,本部分将深入介绍类的相关知识。
类的概念
类是一组事物共有特征和功能的描述。类是对于一组事物的总体描述,是按照面向对象技术进行设计时最小的单位,也是组成项目的最基本的模块。类的概念是抽象的,类似于建筑设计中的图纸,是对于现实需要代表的具体内容的抽象。类只包含框架结构,而不包含具体的数据。所以类代表的是总体,而不代表某个特定的个体。
我的总结:类是抽象的,对象是具体的,实实在在的!
类的定义:
[修饰符] class 类名{
1~n个构造方法;
0~n个字段;
0~n个方法
}
定义类,其实就是定义类里面的对象
对象包含:
状态;(属性)
功能、行为;(方法)
通过类来描述对象;
状态--------成员变量;
功能、行为——方法;
Eg:
class Person{
//属性
private String name;
private int age;
private int sal;
//方法
public void show(){
System.out.println("个人情况:"+name+age+sal);
}
}
3、构造方法
构造方法:用来构造类的实例(每一个类都默认有一个无参的构造方法,得使用new调用)
字段:类或对象所包含的数据,对类状态的一种描述;
方法:类或对象的特征或行为
作用:
给类中的字段进行初始化,可以用来创建对象。
特点:
方法名与类名相同
不用定义返回值类型
不需要写return语句
我的总结:
注意:
默认构造方法的特点。
多个构造方法是以重载的形式存在的。
构造方法的重载:(需要哪个就去适配哪个,调用哪个)
this([实参]);调用当前类的构造方法
注意: this([实参]);必须放在构造器的第一行;
对象的产生格式:
类名称 对象名 = new 类名称();
因为有(),所以是方法,实际上它就是构造方法,并且是非私有的构造方法。
如:CellPhone cp = new CellPhone();
Eg:
class Person{
private String name;
private int age;
private int sal;
public void show(){
System.out.println("个人情况:"+name+age+sal);
}
public Person(String name) {
super();
this.name = name;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person(String name, int age, int sal) {
super();
this.name = name;
this.age = age;
this.sal = sal;
}
}
4、static关键字
特点:
随着类的加载而加载
优先于对象存在
被所有对象所共享
可以直接被类名调用
使用注意:
静态方法只能访问静态成员
但是非静态成员可以访问静态成员;
静态方法中不可以使用this,super关键字
主方法(main)是静态的(可以利用类名去调用静态的main方法,很正常!但是会陷入死循环,导致内存溢出,jvm自动停止!)
public static void main(String[] agrs){}
可修饰字段,方法。
用static 修饰的成员表示它属于这个类共有,而不是属于该类的单个实例。
static 修饰的字段 == 类字段
static 修饰的方法 == 类方法
没使用static修饰的字段和方法,成员属于类的单个实例,
不属于类。
没有static 修饰的字段 == 实例字段
没有static 修饰的方法 == 实例方法
类和实例访问字段和方法的语法:
访问类成员: 类.字段 类.方法
访问实例成员: 实例.字段 实例.方法
我的总结:
static 修饰的字段和方法,既可以通过类调用,也可以使用实例调用;
没static 修饰的字段和方法,只能使用实例来调用(建议使用:类名来调用;其实在底层,对象调用类成员,也会转换类名调用)
static关键字不能与this,super同时连用!
5、匿名对象
一个没有名字的对象, 创建了一个对象出来,没有赋给一个变量;
特点:
对方法或字段只进行一次调用时;
可作为实际参数进行传递;
只在堆里面开辟存储区域,
只能使用一次, 使用完就被销毁了;
何时使用?只拿来用一次!!
new Person();表示匿名对象,没有名字的对象
new Person().age = 17;//使用一次之后就被销毁了
6、this关键字
特点:this表示当前对象。
当前对象 ←→ 当前正在调用实例成员的对象
换言之:谁调用了方法,谁就是当前对象。
什么时候使用this关键字呢?
方法间的相互调用;
this.字段;
构造器中相互调用,但是此时this([参数])必须写在构造方法第一行。
this不能用在static修饰的方法里和static修饰的代码块里;
Eg:构造方法中的this.name = name;
7、面向对象之封装
封装的两个含义:
1.把对象的状态和行为看成一个统一的整体,将二者存放在一个独立的模块中(类);
2."信息隐藏", 把不需要让外界知道的信息隐藏起来,尽可能隐藏对象功能实现细节,字段;
封装机制在程序中的体现是:把描述对象的状态用字段表示,描述对象的行为用方法表示,把字段和方法定义在一个类中,并保证外界不能任意更改其内部的字段值,也不允许任意调动其内部的功能方法。
程序中的一种体现:通常将类中的成员变量私有化(private),通过对外提供方法(setXxx,getXxx),可对该变量(xxx)进行访问。
boolean 类型的变量没有getXX,只有 isXX;
Eg:
class Person1{
private String name;
private int age;
private int sal;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
8、访问修饰符
private 类访问权限:本类内部可以访问,不能继承到子类;
default 什么都不写,包访问权限:本类内部可以访问,同包其他类也可以访问,同包可继承;
protected 子类访问权限:本类内部可以访问,不同包的子类也可以访问,同包其他类也可以访问,能继承到子类;
public 公共访问权限:任何地方都可以访问,能继承到子类;
我的总结:
9、类的设计分析
分析思路:
根据要求写出类所包含的字段;
所有的字段都必须私有化;
封装之后的字段可通过setter和getter设值和取得;
按需求可添加若干构造方法;
根据需求可添加相应的方法;
类中的所有方法都不要直接处理(输出打印),而是交给调用者去处理。
10、面向对象之继承
首先有反映一般事物特性的类,然后在此基础上反映出特殊事物的类;
也就是说:继承是一种从一般到特殊的关系;
特点:
1、提高了代码的复用性。
2、让类与类之间产生关系,有了这个继承关系才有了多态的特性。
3、Java语言中只支持单继承(有别于C语言)。
因为多继承容易带来安全隐患(父类多了, 功能相同的话,就会出现调用不确定性吗,覆写一个方法,到底覆写的谁的?)。
ps:接口可以实现多继承
4、Java支持多层继承,object是每个类的超类,实现树形结构。
我的总结:
继承是多态的前提。
对类而言,只支持单继承。接口可以实现多继承
格式:
[修饰符] class SubClass extends SuperClass
按照这种关系,我们把SuperClass类称为父类或基类,把SubClass称为子类或派生类或拓展类;
我的总结:
java.lang.Object是所有类的父类,
Object要么是直接父类要么是间接父类。
Eg:
学生属于人的一种特殊情况,此时我把人的共性写在Person类里面,为了让学生拥有这些共性(别的比如老师也可以有这些共性),然后我就让学生来拓展Person类。
我的总结:
子类与父类的关系:
子类拓展父类(子类是父类的一种特殊情况)
主要是以父类为基础,然后添加属于自己的字段和方法。
父类的私有成员子类不能继承到;父类的构造方法不能被继承;
Java只支持单继承,不支持多继承;//不然的话,比如show方法,继承了多个,不知道到底调用那一个。
一个类有且只有一个直接父类;
一个类没显示的继承其他的一个类的时候,默认的直接父类就是Object类;
Student 的直接父类是Person,Object类也是Student类的父类,但是是间接父类;
一旦一个类显示的继承了其他的一个类的时候,此时默认的直接父类Object就会被取消;
Java里一个类只能有一个直接父类;java.lang.Object是所有类的父类,Object要么是直接父类要么是间接父类。
子类对象实例化过程
在继承操作中,对于子类对象的实例化:
子类对象在实例化之前必须首先调用父类中的构造方法之后再调用自身的构造方法。
11、子类访问父类和方法覆写
子类不能直接访问父类的私有成员;
但是子类可以调用父类中的非私有方法来间接访问父类的私有成员。
Person类中有私有字段name,Student继承Person
new Sudent().name; ×
new Student().getName(); √
子类拓展父类(子类是父类的一种特殊情况)
主要是以父类为基础,然后添加属于自己的字段和方法。
方法覆写产生原因:
当父类中某个方法不适合于子类时,子类出现父类一模一样的方法.
判断必杀技:子类方法前加上@Override能编译通过,表明是方法的覆写。
调用被覆盖的父类方法:使用super.方法名(实参);
方法覆写时应遵循的原则(一同两小一大):
(一同):方法签名必须相同;
(两小):
子类方法的返回值类型比父类方法的返回值类型更小或相等
子类方法声明抛出的异常应比父类方法申明抛出的异常更小或相等;
(一大):子类方法的访问权限应比父类方法更大或相等;
子类需要覆写父类方法。
当父类的某个方法不适合于子类本身的特征行为时就当覆写父类中应当改变的方法。
12、super关键字和调用父类构造方法
表示父类对象的默认引用
如果子类要调用父类被覆盖的实例方法,可用super作为调用者调用父类被覆盖的实例方法。
使用super调用父类方法
使用super调用父类的构造方法
调用构造方法
本类中调用另一个重载构造方法用this(参数列表)
子类构造方法调用父类构造方法用super(参数列表)
子类调用父类的构造方法时:
super必须放在第一句
Java在执行子类的构造方法前会先调用父类无参的构造方法,其目的是为了对继承自父类的成员做初始化操作。
子类在创建对象的时候,默认调用父类的无参构造方法,要是子类构造方法中显示指定调用父类其他构造方法,就调用指定的父类构造方法,取消调用父类无参构造方法。
Eg:
package reviewDemo;
class A{
String name;
A(){
System.out.println("父类默认隐式的构造方法!");
}
A(String name){
System.out.println("父类显式的构造方法!");
}
}
class B extends A{
B(){
super(null);
System.out.println("子类默认隐式的构造方法!");
}
}
public class Demo10 {
public static void main(String[] args) {
new B();
}
}
结果:父类显式的构造方法!
子类默认隐式的构造方法!
13、面向对象之多态
多态:指同一个实体同时具有多种形式
好比,你去面馆吃面,说我要吃面,那么;老板给我牛肉面,鸡蛋面等都可以,
这就是说"面"有多种形态,也就是说实体有多种形态;
编译时的类型由声明该变量时使用的类型决定,运行时的类型由实际赋给变量的对象决定。
如果编译时类型和运行时类型不同,就出现多态。
Eg:
前提:Student extends Person:
Person p = new Person();
Student s = new Student();
Person p = new Student();//多态
引用关系:父类变量指向子类实例对象
实现多态的机制:
父类的引用变量可以指向子类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的真正实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
多态的作用:
把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,以适应需求的不断变化。
只修改方法的实现,不必修改方法的声明
继承是多态产生的前提条件;
分类:
编译时多态:方法重载
运行时多态:方法覆写
Eg:
package test;
class Dog{
void eat(){
System.out.println("一般的狗吃一般的狗粮!");
}
}
class HashDog extends Dog{
void eat(){
System.out.println("哈士奇吃哈士奇的狗粮!");
}
}
class ZangAoDog extends Dog{
void eat(){
System.out.println("藏獒吃藏獒的狗粮!");
}
}
//定义一个动物园喂的方法
class Zoo{
void feed(Dog d){
d.eat();
}
}
public class Demo11 {
public static void main(String[] args) {
Dog hd = new HashDog();
Dog zd = new ZangAoDog();
Zoo z = new Zoo();
z.feed(hd);
z.feed(zd);
}
}
输出:
哈士奇吃哈士奇的狗粮!
藏獒吃藏獒的狗粮!
14、引用变量类型转换
向上转型(子类→父类):(自动完成)
父类名称 父类对象 = 子类实例 ;
向下转型(父类→子类):(强制完成)
子类名称 子类对象 = (子类名称)父类实例 ;
对象名 instanceof 类
判断指定的变量名此时引用的真正类型是不是当前给出的类或子类;
我的总结:对象的类型和类必须有继承关系
Eg:
class A extends B{}
B b = new A();
If(b instanceof A){ ...
}
四、黑马程序员—面向对象(2)
第四篇:
1、基本数据类型的包装类
引言:Java提倡的万物皆对象,但是数据类型的划分出现了基本数据类型和引用数据类型,那么我们怎么能把基本数据类型称为对象呢?
除了Integer和Character定义的名称和对应的基本类型差异大,其他六种都是将首字母大写就可以了。
Integer,Byte,Float,Double,Short,Long都是Number类的子类。(Number类后面讲);
Character和Boolean都是Object直接子类;
8个类都是final修饰的(不可被继承)。
2、基本数据类型和包装类相互转换
把基本数据类型 → 包装类:
通过对应包装类的构造方法实现
除了Character外,其他包装类都可以传入一个字符串参数构建包装类对象。
包装类 → 基本数据类型
包装类的实例方法xxxValue(); // xxx表示包装类对应的基本数据类型
Eg:
boolean bool = false;
Boolean b2 = new Boolean(bool);
Integer i = new Integer(3);
int i2 = i.intValue();
Boolean b1 = new Boolean("TRue");//true
boolean b2 = b1.booleanValue();
Float f = new Float("3.14");//3.14
Integer i2 = new Integer("123s");//NumberFormatException
备注:
自动装箱&自动拆箱
jdk1.5开始出现的特性:
自动装箱:可把一个基本类型变量直接赋给对应的包装类对象或则Object对象
自动拆箱:允许把 包装类对象直接赋给对应的基本数据类型
Eg:
Integer i = 3;//装箱
int i2 = i;//拆箱
Object flag = new Boolean(false);
if(flag instanceof Boolean){
Boolean b = (Boolean)flag;
boolean b2 = b;
}
我的总结:对于基本数据类型和包装类之间的装换,我们可以直接的用,相互转换,因为java5之后的自动拆箱、装箱功能!即便不知道这个,其实使用中也不影响!
3、基本类型和String之间的转换
String → 基本类型,除了Character外所有的包装类提供parseXxx(String s)静态方法,用于把一个特定的字符串转换成基本类型变量;
基本类型 → String,String 类有静态方法valueOf(),用于将基本类型的变量转换成String类型。
String str = "17";
int i = Integer.parseInt(str);//String --> 基本类型
String s1 = String.valueOf(i);//基本类型 --> String
我的总结:这个从后续的学习来看,用处不大,记住有这样的方法就行,查api!
4、Object类
所有类的公共父类,一旦一个类没有显示地继承一个类则其直接父类一定是Object。
一切数据类型都可用Object接收
class OOXX extends Object{}等价于class ooXX {}
常见方法
public boolean equals(Object obj):对象比较
public int hashCode():取得该对象的Hash码
public String toString():对象描述
Object类的 toString()方法:“对象的描述”
建议所有类都覆写此方法
直接打印输出对象时,会调用该对象的toString()方法。//可以不写出来
打印对象的时候,实际调用的对象实际指向的类的自我描述;
全限定类名+@+十六进制的hashCode值,等价于
全限定类名+@+IntegertoHexString(该对象.hashCode)
equals也是判断是否指向同一个对象
没有实际意义,有必要可以重写
public boolean equals(Object obj) {}
String 覆写了 Object的equals方法:只比较字符的序列是否相同
==用于判断两个变量是否相等
基本类型:
引用类型:必须指向同一个对象,才true
只能比较有父子或平级关系的两个对象
new String("1") == new String("1"); ?
5、代码块
代码块指的是使用"{}"括起来的一段代码,根据代码块存在的位置可以分为4种:
普通代码块;
构造代码块;
静态代码块;
同步代码块(线程同步的时候讲解)。
代码块里变量的作用域:
只在自己所在区域(前后的{})内有效;
普通代码块:
普通代码块就是直接定义在方法或语句中定义的代码块:
public void show(){
普通代码块
}
构造代码块:
直接写在类中的代码块:
优先于构造方法执行,每次实例化对象之前都会执行构造代码块。
Eg:
public class Demo {
{
System.out.println("我是构造代码块");
}
public Demo(){
System.out.println("我是构造方法");
}
public static void main(String[] args) {
Demo d1 = new Demo();
Demo d2 = new Demo();
}
}
静态代码块
使用static 修饰的构造代码块:
优先于主方法执行,优先于构造代码块执行,不管有创建多少对象,静态代码块只执行一次,可用于给静态变量赋值;
Eg:
package reviewDemo;
/**
* 测试各代码块的优先级
*优先级顺序:静态代码块 > 构造代码块 > 普通代码块
*备注:无论创建几个对象,静态代码块只执行一次!
*/
public class Demo13 {
Demo13(){
System.out.println("我是构造方法!");
}
{
System.out.println("我是构造代码块!");//实例化对象的时候才会去调用!
}
static{
System.out.println("我是静态代码块!");
}
public static void main(String[] args) {
new Demo13();
new Demo13();//再次创建对象,证明无论创建几次对象,静态代码块都只执行一次
System.out.println("我是普通代码块!");
}
}
输出:
我是静态代码块!
我是构造代码块!
我是构造方法!
我是构造代码块!
我是构造方法!
我是普通代码块!
我的总结:这个例子非常好!
6、构造方法的私有化
有的时候我们为了避免外界创建某类的实例,就将某类的构造方法私有化,即将它的构造方法用private修饰:
外界如何用到?
提供get方法!不提供的话外界就没法创建对象!(对反射无效)
Eg:package reviewDemo;
class Stu{
//将构造方法私有化
private Stu(){
}
}
public class Demo15 {
public static void main(String[] args) {
Stu s = new Stu();
}
}
7、Singleton模式(单例模式) 饿汉式和懒汉式
目的:整个应用中有且只有一个实例,所有指向该类型实例的引用都指向这个实例。
好比一个国家就只有一个皇帝(XXX),此时每个人叫的“皇帝”都是指叫的XXX本人;
常见单例模式类型:
饿汉式单例:直接将对象定义出来
懒汉式单例:只给出变量,并不将其初始化;
我的总结:
饿汉式,static修饰,随着类的加载而加载,会损耗性能,但是方法相对简单
懒汉式 第一次用的时候相对较慢,因为需要加载!线程,不安全!
package reviewDemo;
//单例模式
//饿汉式,直接把对象构造出来
class SingleDemo{
private static SingleDemo s1 = new SingleDemo();
private SingleDemo(){
//提供私有化的构造方法,那么外界就不能构造对象了!
}
public static SingleDemo getS1() {
return s1;
}
}
//懒汉式,先定义,但是不创建对象
class SingleDemo2{
private static SingleDemo2 s3 ;
private SingleDemo2(){
//提供私有化的构造方法,那么外界就不能构造对象了!
}
public static SingleDemo2 getS3() { //这是一个方法,返回值为创建的对象!
if(s3 == null){
s3 = new SingleDemo2();
}//和饿汉式的区别,此时才来创建对象!
return s3;
}
}
public class Demo14 {
public static void main(String[] args) {
SingleDemo s1 = SingleDemo.getS1();
SingleDemo s2 = SingleDemo.getS1();
SingleDemo2 s3 = SingleDemo2.getS3();
SingleDemo2 s4 = SingleDemo2.getS3();
System.out.println(s1 == s2);
System.out.println(s3 == s4);
}
}
输出:true true
备注:枚举更加安全些
package reviewDemo;
enum Stu{
jake;
//将构造方法私有化起来,反射也不能创建对象,安全
private Stu(){
}
}
public class Demo15 {
public static void main(String[] args) {
}
}
8、final 关键字
① final可以修饰类,方法,变量。
② final修饰类不可以被继承,但是可以继承其他类。
③ final修饰的方法不可以被覆写,但可以覆写父类方法。
④ final修饰的变量称为常量,这些变量只能赋值一次。
⑤ 内部类在局部时,只可以访问被final修饰的局部变量。
⑥ final修饰的引用类型变量,表示该变量的引用不能变,而不是该变量的值不能变;
Eg:
package reviewDemo;
final class Name{
}
class NewName extends Name{ //ERROR,报错,因为Name