1、抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。
2、继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到继承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要手段。
3、封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。
4、多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。如果将对象的方法视为对象向外界提供的服务,那么运行时的多态性可以解释为:当A系统访问B系统提供的服务时,B系统有多种提供服务的方式,但一切对A系统来说都是透明的(就像电动剃须刀是A系统,它的供电系统是B系统,B系统可以使用电池供电或者用交流电,甚至还有可能是太阳能,A系统只会通过B类对象调用供电的方法,但并不知道供电系统的底层实现是什么,究竟通过何种方式获得了动力)。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事:1. 方法重写(子类继承父类并重写父类中已有的或抽象的方法);2. 对象造型(用父类型引用引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。
Java源程序(.java)要先编译成与平台无关的字节码文件(.class),然后字节码文件再解释成机器码运行。解释是通过Java虚拟机来执行的。
字节码文件不面向任何具体平台,只面向虚拟机。
Java虚拟机是可运行Java字节码文件的虚拟计算机。不同平台的虚拟机是不同的,但它们都提供了相同的接口。
Java语言具有一次编译,到处运行的特点。就是说编译后的.class可以跨平台运行,前提是该平台具有相应的Java虚拟机。但是性能比C/C++要低。
语言层次的安全性主要体现在:
Java取消了强大但又危险的指针,而代之以引用。由于指针可进行移动运算,指针可随便指向一个内存区域,而不管这个区域是否可用,这样做是危险的,因为原来这个内存地址可能存储着重要数据或者是其他程序运行所占用的,并且使用指针也容易数组越界。
垃圾回收机制:不需要程序员直接控制内存回收,由垃圾回收器在后台自动回收不再使用的内存。避免程序忘记及时回收,导致内存泄露。避免程序错误回收程序核心类库的内存,导致系统崩溃。
异常处理机制:Java异常机制主要依赖于try、catch、finally、throw、throws五个关键字。
强制类型转换:只有在满足强制转换规则的情况下才能强转成功。
底层的安全性可以从以下方面来说明
Java在字节码的传输过程中使用了公开密钥加密机制(PKC)。
在运行环境提供了四级安全性保障机制:
字节码校验器 -类装载器 -运行时内存布局 -文件访问限制
Java2平台包括标准版(J2SE)、企业版(J2EE)和微缩版(J2ME)三个版本:
Standard Edition(标准版) J2SE 包含那些构成Java语言核心的类。
比如:数据库连接、接口定义、输入/输出、网络编程
Enterprise Edition(企业版) J2EE 包含J2SE 中的类,并且还包含用于开发企业级应用的类。
比如servlet、JSP、XML、事务控制
Micro Edition(微缩版) J2ME 包含J2SE中一部分类,用于消费类电子产品的软件开发。
比如:呼机、智能卡、手机、PDA、机顶盒
他们的范围是:J2SE包含于J2EE中,J2ME包含了J2SE的核心类,但新添加了一些专有类
应用场合,API的覆盖范围各不相同。
JVM :JVM是Java Virtual Machine(Java虚拟机)的缩写,它是整个java实现跨平台的最核心的部分,所有的java程序会首先被编译为.class的类文件,这种类文件可以在虚拟机上执行,也就是说class并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行。JVM是Java平台的基础,和实际的机器一样,它也有自己的指令集,并且在运行时操作不同的内存区域。 JVM通过抽象操作系统和CPU结构,提供了一种与平台无关的代码执行方法,即与特殊的实现方法、主机硬件、主机操作系统无关。JVM的主要工作是解释自己的指令集(即字节码)到CPU的指令集或对应的系统调用,保护用户免被恶意程序骚扰。 JVM对上层的Java源文件是不关心的,它关注的只是由源文件生成的类文件(.class文件)。
JRE:JRE是java runtime environment(java运行环境)的缩写。光有JVM还不能让class文件执行,因为在解释class的时候JVM需要调用解释所需要的类库lib。在JDK的安装目录里你可以找到jre目录,里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和lib和起来就称为jre。所以,在你写完java程序编译成.class之后,你可以把这个.class文件和jre一起打包发给朋友,这样你的朋友就可以运行你写程序了(jre里有运行.class的java.exe)。JRE是Sun公司发布的一个更大的系统,它里面就有一个JVM。JRE就与具体的CPU结构和操作系统有关,是运行Java程序必不可少的(除非用其他一些编译环境编译成.exe可执行文件……),JRE的地位就象一台PC机一样,我们写好的Win32应用程序需要操作系统帮我们运行,同样的,我们编写的Java程序也必须要JRE才能运行。
JDK:JDK是java development kit(java开发工具包)的缩写。每个学java的人都会先在机器上装一个JDK,那 让我们看一下JDK的安装目录。在目录下面有六个文件夹、一个src类库源码压缩包、和其他几个声明文件。其中,真正在运行java时起作用的是以下四个文件夹:bin、include、lib、jre。现在我们可以看出这样一个关系,JDK包含JRE,而JRE包含JVM。
bin:最主要的是编译器(javac.exe)
include:java和JVM交互用的头文件
lib:类库
jre:java运行环境
(注意:这里的bin、lib文件夹和jre里的bin、lib是不同的)总的来说JDK是用于java程序的开发,而jre则是只能运行class而没有编译的功能。eclipse、idea等其他IDE有自己的编译器而不是用JDK bin目录中自带的,所以在安装时你会发现他们只要求你选jre路径就ok了。
共有单行注释、多行注释、文档注释3种注释类型。使用如下:
单行注释,采用“//”方式.只能注释一行代码。如://类成员变量
多行注释,采用“/*...*/”方式,可注释多行代码,其中不允许出现嵌套。如:
/*System.out.println("a");
System.out.println("b");
System.out.println("c");*/
文档注释,采用“/**...*/”方式。如:
/**
* 子类 Dog
* @author Administrator
**/
public class Dog extends Animal{}
数据类型 | 关键字 | 字节数 | |
数值型 | 整数型 | byte | 1 |
short | 2 | ||
int | 4 | ||
long | 8 | ||
浮点型 | float | 4 | |
double | 8 | ||
布尔型 | boolean | 1(位) | |
字符型 | char | 2 |
共同点:
1、i++和++i都是变量自增1,都等价于i=i+1
2、如果i++,++i是一条单独的语句,两者没有任何区别
3、i++和++i的使用仅仅针对变量。 5++和++5会报错,因为5不是变量。
不同点:
如果i++,++i不是一条单独的语句,他们就有区别i++ :先运算后增1。如:
int x=5;
int y=x++;
System.out.println("x="+x+", y="+y);
//以上代码运行后输出结果为:x=6, y=5
++i : 先增1后运算。如:
int x=5;
int y=++x;
System.out.println("x="+x+", y="+y);
//以上代码运行后输出结果为:x=6, y=6
&和&&的联系(共同点):
&和&&都可以用作逻辑与运算符,但是要看使用时的具体条件来决定。
操作数1&操作数2,操作数1&&操作数2,
表达式1&表达式2,表达式1&&表达式2,
情况1:当上述的操作数是boolean类型变量时,&和&&都可以用作逻辑与运算符。
情况2:当上述的表达式结果是boolean类型变量时,&和&&都可以用作逻辑与运算符。
表示逻辑与(and),当运算符两边的表达式的结果或操作数都为true时,整个运算结果才为true,否则,只要有一方为false,结果都为false。
&和&&的区别(不同点):
(1)、&逻辑运算符称为逻辑与运算符,&&逻辑运算符称为短路与运算符,也可叫逻辑与运算符。
对于&:无论任何情况,&两边的操作数或表达式都会参与计算。
对于&&:当&&左边的操作数为false或左边表达式结果为false时,&&右边的操作数或表达式将不参与计算,此时最终结果都为false。
综上所述,如果逻辑与运算的第一个操作数是false或第一个表达式的结果为false时,对于第二个操作数或表达式是否进行运算,对最终的结果没有影响,结果肯定是false。推介平时多使用&&,因为它效率更高些。
、&还可以用作位运算符。当&两边操作数或两边表达式的结果不是boolean类型时,&用于按位与运算符的操作。
|和||的区别和联系与&和&&的区别和联系类似
相同之处:都是分支语句,多超过一种的情况进行判断处理。
不同之处:
switch更适合用于多分支情况,就是有很多种情况需要判断处理,判断条件类型单一,只有一个入口,在分支执行完后(如果没有break跳出),不加判断地执行下去;而if—elseif---else多分枝主要适用于分支较少的分支结构,判断类型不是单一,只要一个分支被执行后,后边的分支不再执行。switch为等值判断(不允许比如>= <=),而if为等值和区间都可以,if的使用范围大。
while先判断后执行,第一次判断为false,循环体一次都不执行
do while先执行 后判断,最少执行1次。
如果while循环第一次判断为true, 则两种循环没有区别。
break: 结束当前循环并退出当前循环体。
break还可以退出switch语句
continue: 循环体中后续的语句不执行,但是循环没有结束,继续进行循环条件的判断(for循环还会i++)。continue只是结束本次循环。
递归算法是一种直接或者间接地调用自身算法的过程。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。
递归算法解决问题的特点:
(1) 递归就是在过程或函数里调用自身。
(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
(3) 递归算法解题通常显得很简洁,但运行效率较低。所以一般不提倡用递归算法设计程序。
(4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序。
数组是(相同类型数据)的(有序)(集合)
数组会在内存中开辟一块连续的空间,每个空间相当于之前的一个变量,称为数组的元素element
元素的表示 数组名[下标或者索引] scores[7] scores[0] scores[9]
索引从0开始
每个数组元素有默认值 double 0.0 boolean false int 0
数组元素有序的,不是大小顺序,是索引 的顺序
数组中可以存储基本数据类型,可以存储引用数据类型;但是对于一个数组而言,数组的类型是固定的,只能是一个
length:数组的长度
数组的长度是固定的,一经定义,不能再发生变化(数组的扩容)
冒泡排序
快速排序
插入排序
类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间。类是用于创建对象的蓝图,它是一个定义包括在特定类型的对象中的方法和变量的软件模板。
类和对象好比图纸和实物的关系,模具和铸件的关系。
比如人类就是一个概念,人类具有身高,体重等属性。人类可以做吃饭、说话等方法。
小明就是一个具体的人,也就是实例,他的属性是具体的身高180cm,体重80kg,他做的方法是具体的吃了一碗白米饭,说了“哈哈”这样一句话。
两者都是软件开发思想,先有面向过程,后有面向对象。在大型项目中,针对面向过程的不足推出了面向对象开发思想。
区别:
1.面向过程:事务比较简单,可以用线性的思维去解决
2.面向对象:事务比较复杂,使用简单的线性思维无法解决
共同的:
面向过程和面向对象都是解决实际问题的一种思维方式,两者相辅相成,并不是对立的,解决复杂问题,通过面向对象方式便于我们从宏观上把握事物之间复杂的关系,方便我们分析整个系统,具体到微观操作,任然使用面向过程方式来处理
面向过程是蛋炒饭,面向对象是盖浇饭。盖浇饭的好处就是“菜”“饭”分离,从而提高了制作盖浇饭的灵活性。饭不满意就换饭,菜不满意换菜。用软件工程的专业术语就是“可维护性”比较好,“饭” 和“菜”的耦合度比较低。
区别
编程思路不同: 面向过程以实现功能的函数开发为主,而面向对象要首先抽象出类、属性及其方法,然后通过实例化类、执行方法来完成功能。
封装性:都具有封装性,但是面向过程是封装的是功能,而面向对象封装的是数据和功能。
面向对象具有继承性和多态性,而面向过程没有继承性和多态性,所以面向对象优势是明显。
方法重载和方法重写(覆盖)的区别
英文 | 位置不同 | 作用不同 | |
重载 | overload | 同一个类中 | 在一个类里面为一种行为提供多种实现方式并提高可读性 |
重写 | override | 子类和父类间 | 父类方法无法满足子类的要求,子类通过方法重写满足要求 |
修饰符 | 返回值 | 方法名 | 参数 | 抛出异常 | |
重载 | 无关 | 无关 | 相同 | 不同 | 无关 |
重写 | 大于等于 | 小于等于 | 相同 | 相同 | 小于等于 |
this是对象内部指代自身的引用,同时也是解决成员变量和局部变量同名问题;this可以调用成员变量,不能调用局部变量;this也可以调用成员方法,但是在普通方法中可以省略this,在构造方法中不允许省略,必须是构造方法的第一条语句。,而且在静态方法当中不允许出现this关键字。
super代表对当前对象的直接父类对象的引用,super可以调用直接父类的成员变量(注意权限修饰符的影响,比如不能访问private成员)
super可以调用直接父类的成员方法(注意权限修饰符的影响,比如不能访问private成员);super可以调用直接父类的构造方法,只限构造方法中使用,且必须是第一条语句。
static可以修饰变量、方法、代码块和内部类
static属性属于这个类所有,即由该类创建的所有对象共享同一个static属性。可以对象创建后通过对象名.属性名和类名.属性名两种方式来访问。也可以在没有创建任何对象之前通过类名.属性名的方式来访问。
static变量和非static变量的区别(都是成员变量,不是局部变量)
1.在内存中份数不同
不管有多少个对象,static变量只有1份。对于每个对象,实例变量都会有单独的一份
static变量是属于整个类的,也称为类变量。而非静态变量是属于对象的,也称为实例变量
2.在内存中存放的位置不同
2.在内存中存放的位置不同
3.访问的方式不同
实例变量: 对象名.变量名 stu1.name="小明明";
静态变量:对象名.变量名 stu1.schoolName="西二旗小学"; 不推荐如此使用
类名.变量名 Student.schoolName="东三旗小学"; 推荐使用
4.在内存中分配空间的时间不同
Student.schoolName="东三旗小学";或者Student stu1 = new Student("小明","男",20,98);
static方法也可以通过对象名.方法名和类名.方法名两种方式来访问
static代码块。当类被第一次使用时(可能是调用static属性和方法,或者创建其对象)执行静态代码块,且只被执行一次,主要作用是实现static属性的初始化。
static内部类:属于整个外部类,而不是属于外部类的每个对象。不能访问外部类的非静态成员(变量或者方法),.可以访问外部类的静态成员
final和abstract是功能相反的两个关键字,可以对比记忆
abstract可以用来修饰类和方法,不能用来修饰属性和构造方法;使用abstract修饰的类是抽象类,需要被继承,使用abstract修饰的方法是抽象方法,需要子类被重写。
final可以用来修饰类、方法和属性,不能修饰构造方法。使用final修饰的类不能被继承,使用final修饰的方法不能被重写,使用final修饰的变量的值不能被修改,所以就成了常量。
特别注意:final修饰基本类型变量,其值不能改变,由原来的变量变为常量;但是final修饰引用类型变量,栈内存中的引用不能改变,但是所指向的堆内存中的对象的属性值仍旧可以改变。例如:
package com.xxx;
class Test {
public static void main(String[] args) {
final Dog dog = new Dog("欧欧");
dog.name = "美美";//正确
dog = new Dog("亚亚");//错误
}
}
final修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承例如:String类、Math类等。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重写,但是能够重载。 使用final修饰的对象,对象的引用地址不能变,但是对象的值可以变!
finally在异常处理时提供 finally 块来执行任何清除操作。如果有finally的话,则不管是否发生异常,finally语句都会被执行。一般情况下,都把关闭物理连接(IO流、数据库连接、Socket连接)等相关操作,放入到此代码块中。
finalize方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要清理工作。finalize() 方法是在垃圾收集器删除对象之前被调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。 一般情况下,此方法由JVM调用,程序员不要去调用!
(1)public boolean equals(java.lang.Object) //比较对象的地址值是否相等,如果子类重写,则比较对象的内容是否相等;
(2)public native int hashCode() //获取哈希码
(3)public java.lang.String toString() //把数据转变成字符串
(4)public final native java.lang.Class getClass() //获取类结构信息
(5)protected void finalize() throws java.lang.Throwable //垃圾回收前执行的方法
(6)protected native Object clone() throws
java.lang.CloneNotSupportedException //克隆
同一个类 | 同一个包 | 子类 | 所有类 | |
private | * | |||
defailt | * | * | ||
protected | * | * | * | |
public | * | * | * | * |
类的访问权限只有两种
public公共的 可被同一项目中所有的类访问。 (必须与文件名同名)
default默认的 可被同一个包中的类访问。
成员(成员变量或成员方法)访问权限共有四种:
public 公共的 可以被项目中所有的类访问。(项目可见性)
protected 受保护的 可以被这个类本身访问;同一个包中的所有其他的类访问;被它的子类(同一个包以及不同包中的子类)访问。(子类可见性)
default 默认的被这个类本身访问;被同一个包中的类访问。(包可见性)
private 私有的 只能被这个类本身访问。(类可见性)
继承条件下构造方法的调用规则如下:
情况1:如果子类的构造方法中没有通过super显式调用父类的有参构造方法,也没有通过this显式调用自身的其他构造方法,则系统会默认先调用父类的无参构造方法。在这种情况下,写不写“super();”语句,效果是一样的。
情况2:如果子类的构造方法中通过super显式调用父类的有参构造方法,那将执行父类相应构造方法,而不执行父类无参构造方法。
情况3:如果子类的构造方法中通过this显式调用自身的其他构造方法,在相应构造方法中应用以上两条规则。
特别注意的是,如果存在多级继承关系,在创建一个子类对象时,以上规则会多次向更高一级父类应用,一直到执行顶级父类Object类的无参构造方法为止。
“==”是关系运算符,equals()是方法,同时他们的结果都返回布尔值;
“==”使用情况如下:
a) 基本类型,比较的是值
b) 引用类型,比较的是地址
c) 不能比较没有父子关系的两个对象
equals()方法使用如下:
a) 系统类一般已经覆盖了equals(),比较的是内容。
b) 用户自定义类如果没有覆盖equals(),将调用父类的equals (比如是Object),而Object的equals的比较是地址(return (this == obj);)
c) 用户自定义类需要覆盖父类的equals()
注意:Object的==和equals比较的都是地址,作用相同
实现多态的三个条件(前提条件,向上转型、向下转型)
1、继承的存在;(继承是多态的基础,没有继承就没有多态)
2、子类重写父类的方法。(多态下会调用子类重写后的方法)
3、父类引用变量指向子类对象。(涉及子类到父类的类型转换)
向上转型 Student person = new Student()
将一个父类的引用指向一个子类对象,成为向上转型,自动进行类型转换。此时通过父类引用变量调用的方法是子类覆盖或继承父类的方法,而不是父类的方法此时通过父类引用变量无法调用子类特有的方法。
向下转型 Student stu = (Student)person;
将一个指向子类对象的引用赋给一个子类的引用,成为向下转型,此时必须进行强制类型转换。向下转型必须转换为父类引用指向的真实子类类型,,否则将出现ClassCastException,不是任意的强制转换
向下转型时可以结合使用instanceof运算符进行强制类型转换,比如出现转换异常---ClassCastException
传统的C/C++语言,需要程序员负责回收已经分配内存。
显式回收垃圾回收的缺点:
1)程序忘记及时回收,从而导致内存泄露,降低系统性能。
2)程序错误回收程序核心类库的内存,导致系统崩溃。
Java语言不需要程序员直接控制内存回收,是由JRE在后台自动回收不再使用的内存,称为垃圾回收机制,简称GC;
1)可以提高编程效率。
2)保护程序的完整性。
3)其开销影响性能。Java虚拟机必须跟踪程序中有用的对象,确定哪些是无用的。
垃圾回收机制的 特点
1)垃圾回收机制回收JVM堆内存里的对象空间,不负责回收栈内存数据。
2)对其他物理连接,比如数据库连接、输入流输出流、Socket连接无能为力。
3)垃圾回收发生具有不可预知性,程序无法精确控制垃圾回收机制执行。
4)可以将对象的引用变量设置为null,暗示垃圾回收机制可以回收该对象。
现在的JVM有多种垃圾回收 实现算法,表现各异。
垃圾回收机制回收任何对象之前,总会先调用它的finalize方法(如果覆盖该方法,让一个新的引用变量重新引用该对象,则会重新激活对象)。
程序员可以通过System.gc()或者Runtime.getRuntime().gc()来通知系统进行垃圾回收,会有一些效果,但是系统是否进行垃圾回收依然不确定。
永远不要主动调用某个对象的finalize方法,应该交给垃圾回收机制调用。
1) 八个基本数据类型的包装类
基本数据类型 | 包装类 |
byte | Byte |
boolean | Boolean |
short | Short |
char | Character |
int | Integer |
long | Long |
float | Float |
double | Double |
2)为什么为基本类型引入包装类
2.1基本数据类型有方便之处,简单、高效。
2.2但是Java中的基本数据类型却是不面向对象的(没有属性、方法),这在实际使用时存在很多的不便(比如集合的元素只能是Object)。
为了解决这个不足,在设计类时为每个基本数据类型设计了一个对应的类进行包装,这样八个和基本数据类型对应的类统称为包装类(Wrapper Class)。
3) 包装类和基本数据类型之间的转换
3.1包装类------ wrapperInstance.xxxValue() ------>基本数据类型
3.2包装类-------new WrapperClass(primitive)
3.2包装类-------new WrapperClass(primitive)
4) 自动装箱和自动拆箱
JDK1.5提供了自动装箱(autoboxing)和自动拆箱(autounboxing)功能, 从而实现了包装类和基本数据类型之间的自动转换
5) 包装类还可以实现基本类型变量和字符串之间的转换
基本类型变量--->String.valueof()--->字符串 基本类型变量<---WrapperClass.parseXxx(string)---字符串
int是java提供的8种原始数据类型之一,Java为每个原始类型提供了封装类,Integer是java为int提供的封装类。
int是java提供的8种原始数据类型之一,Java为每个原始类型提供了封装类,Integer是java为int提供的封装类。
在Hibernate中,如果将OID定义为Integer类型,那么Hibernate就可以根据其值是否为null而判断一个对象是否是临时的,如果将OID定义为了int类型,还需要在hbm映射文件中设置其unsaved-value属性为0。
另外,Integer提供了多个与整数相关的操作方法,例如,将一个字符串转换成整数,Integer中还定义了表示整数的最大值和最小值的常量。
答: 面向对象的三大特征:封装、继承、多态。
举例:(比如设计一个游戏)我现在创建了一个对象,名叫战士。
战士的属性是—性别,年龄,职业,等级,战斗力,血量。
它的方法—战斗,逃跑,吃饭,睡觉,死。
后来,我又建了一个对象,叫人。
属性:性别,年龄,职业,等级,血量
方法:逃跑,吃饭,睡觉,死。
我让人,成为战士的父类,战士可以直接继承人的属性和方法。
战士修改成—
属性:战斗力。
方法:战斗。
看上去战士的资料变少了,实际上没有,我们仍然可以调用方法—战士.死。
而且我们还可以重载战士.死的方法,简称重载死法。
我还建了一个对象—法师,父类也是人。
属性:法力值
方法:施法,泡妞。
你看,用了继承,创建对象变得更方便了。
再后来,我又建立了一个对象,叫怪物。
属性:等级,战力,血量。
方法:战斗,死。
建了个对象,叫白兔怪,父类怪物,可继承怪物所有的属性和方法。
属性:毛色。
方法:卖萌,吃胡萝卜。
答:
内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比如申请了一个integer,但给它存了long才能存下的数,那就是内存溢出。
内存泄露 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。
memory leak会最终会导致out of memory!
答:Java中的序列化机制能够将一个实例对象(只序列化对象的属性值,而不会去序列化什么所谓的方法。)的状态信息写入到一个字节流中使其可以通过socket进行传输、或者持久化到存储数据库或文件系统中;然后在需要的时候通过字节流中的信息来重构一个相同的对象。一般而言,要使得一个类可以序列化,只需简单实现java.io.Serializable接口即可。
对象的序列化主要有两种用途:
1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
2) 在网络上传送对象的字节序列。
在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。
答:Java创建对象的几种方式(重要):
1、 用new语句创建对象,这是最常见的创建对象的方法。
2、 运用反射手段,调用java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法。
3、 调用对象的clone()方法。
4、运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法。
(1)和(2)都会明确的显式的调用构造函数 ;(3)是在内存上对已有对象的影印,所以不会调用构造函数 ;(4)是从文件中还原类的对象,也不会调用构造函数。
答:匿名内部类是没有名字的内部类,不能继承其它类,但一个内部类可以作为一个接口,由另一个内部类实现.
1、由于匿名内部类没有名字,所以它没有构造函数。因为没有构造函数,所以它必须完全借用父类的构造函数来实例化,换言之:匿名内部类完全把创建对象的任务交给了父类去完成。
2、在匿名内部类里创建新的方法没有太大意义,但它可以通过覆盖父类的方法达到神奇效果,如上例所示。这是多态性的体现。
3、因为匿名内部类没有名字,所以无法进行向下的强制类型转换,持有对一个匿名内部类对象引用的变量类型一定是它的直接或间接父类类型。
(1) 在Java中是使用泛型来约束HashMap中的key和value的类型的,即HashMap< K, V>;而泛型在Java的规定中必须是对象Object类型的,也就是说HashMap< K, V>可以理解为HashMap< Object, Object>,很显然基本数据类型不是Object类型的,因此不能作为键值,只能是引用类型。虽然我们在HashMap中可以这样添加数据:“map.put(1, “Java”);”,但实际上是将其中的key值1进行了自动装箱操作,变为了Integer类型。
(1) 在Java中是使用泛型来约束HashMap中的key和value的类型的,即HashMap< K, V>;而泛型在Java的规定中必须是对象Object类型的,也就是说HashMap< K, V>可以理解为HashMap< Object, Object>,很显然基本数据类型不是Object类型的,因此不能作为键值,只能是引用类型。虽然我们在HashMap中可以这样添加数据:“map.put(1, “Java”);”,但实际上是将其中的key值1进行了自动装箱操作,变为了Integer类型。
实现多态有三个前提条件:
1、 继承的存在;(继承是多态的基础,没有继承就没有多态)。
2、子类重写父类的方法。(多态下会调用子类重写后的方法)。
3、父类引用变量指向子类对象。(涉及子类到父类的类型转换)。
最后使用父类的引用变量调用子类重写的方法即可实现多态。
56.接口和抽象类的区别
抽象类和接口均包含抽象方法,类必须实现所有的抽象方法,否则是抽象类
抽象类和接口都不能实例化,他们位于继承树的顶端,用来被其他类继承和实现
两者的区别主要体现在两方面:语法方面和设计理念方面
语法方面的区别是比较低层次的,非本质的,主要表现在:
接口中只能定义全局静态常量,不能定义变量。抽象类中可以定义常量和变量。
接口中所有的方法都是全局抽象方法。抽象类中可以有0个、1个或多个,甚至全部都是抽象方法。
抽象类中可以有构造方法,但不能用来实例化,而在子类实例化是执行,完成属于抽象类的初始化操作。接口中不能定义构造方法。
一个类只能有一个直接父类(可以是抽象类),但可以充实实现多个接口。一个类使用extends来继承抽象类,使用implements来实现接口。
一个类只能有一个直接父类(可以是抽象类),但可以充实实现多个接口。一个类使用extends来继承抽象类,使用implements来实现接口。
抽象类体现了一种继承关系,目的是复用代码,抽象类中定义了各个子类的相同代码,可以认为父类是一个实现了部分功能的“中间产品”,而子类是“最终产品”。父类和子类之间必须存在“is-a”的关系,即父类和子类在概念本质上应该是相同的。
接口并不要求实现类和接口在概念本质上一致的,仅仅是实现了接口定义的约定或者能力而已。接口定义了“做什么”,而实现类负责完成“怎么做”,体现了功能(规范)和实现分离的原则。接口和实现之间可以认为是一种“has-a的关系”
相同点:
同步方法就是在方法前加关键字synchronized,然后被同步的方法一次只能有一个线程进入,其他线程等待。而同步代码块则是在方法内部使用大括号使得一个代码块得到同步。同步代码块会有一个同步的“目标”,使得同步块更加灵活一些(同步代码块可以通过“目标”决定需要锁定的对象)。
一般情况下,如果此“目标”为this,同步方法和代码块没有太大的区别。
区别:
同步方法直接在方法上加synchronized实现加锁,同步代码块则在方法内部加锁。很明显,同步方法锁的范围比较大,而同步代码块范围要小点。一般同步的范围越大,性能就越差。所以一般需要加锁进行同步的时候,范围越小越好,这样性能更好。
静态内部类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用。
静态内部类可以有静态成员(方法,属性),而非静态内部类则不能有静态成员(方法,属性)。
非静态内部类能够访问外部类的静态和非静态成员。静态内部类不能访问外部类的非静态成员,只能访问外部类的静态成员。
实例化方式不同:
1) 静态内部类:不依赖于外部类的实例,直接实例化内部类对象
2) 非静态内部类:通过外部类的对象实例生成内部类对象
反射的概念:
反射,一种计算机处理方式。是程序可以访问、检测和修改它本身状态或行为的一种能力。
Java反射可以于运行时加载,探知和使用编译期间完全未知的类.
程序在运行状态中, 可以动态加载一个只有名称的类, 对于任意一个已经加载的类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能调用他的任意一个方法和属性;
加载完类之后, 在堆内存中会产生一个Class类型的对象(一个类只有一个Class对象), 这个对象包含了完整的类的结构信息,而且这个Class对象就像一面镜子,透过这个镜子看到类的结构,所以被称之为:反射.
java反射使得我们可以在程序运行时动态加载一个类,动态获取类的基本信息和定义的方法,构造函数,域等。
除了检阅类信息外,还可以动态创建类的实例,执行类实例的方法,获取类实例的域值。反射使java这种静态语言有了动态的特性。
反射的作用:
通过反射可以使程序代码访问装载到JVM 中的类的内部信息
1) 获取已装载类的属性信息
2) 获取已装载类的方法
3) 获取已装载类的构造方法信息
反射的优点:
增加程序的灵活性。
如struts中。请求的派发控制。
当请求来到时。struts通过查询配置文件。找到该请求对应的action。已经方法。
然后通过反射实例化action。并调用响应method。
如果不适用反射,那么你就只能写死到代码里了。
所以说,一个灵活,一个不灵活。
很少情况下是非用反射不可的。大多数情况下反射是为了提高程序的灵活性。因此一般框架中使用较多。因为框架要适用更多的情况。对灵活性要求较高。
接口可以继承接口,抽象类可以实现接口,抽象类可以继承实体类。
int是java提供的8种原始数据类型之一。Java为每个原始类型提供了封装类,Integer是java为int提供的封装类。int的默认值为0,而Integer的默认值为null,即Integer可以区分出未赋值和值为0的区别,int则无法表达出未赋值的情况,例如,要想表达出没有参加考试和考试成绩为0的区别,则只能使用Integer。在JSP开发中,Integer的默认为null,所以用el表达式在文本框中显示时,值为空白字符串,而int默认的默认值为0,所以用el表达式在文本框中显示时,结果为0,所以,int不适合作为web层的表单数据的类型。
在Hibernate中,如果将OID定义为Integer类型,那么Hibernate就可以根据其值是否为null而判断一个对象是否是临时的,如果将OID定义为了int类型,还需要在hbm映射文件中设置其unsaved-value属性为0。另外,Integer提供了多个与整数相关的操作方法,例如,将一个字符串转换成整数,Integer中还定义了表示整数的最大值和最小值的常量。
&和&&的联系(共同点):
&和&&都可以用作逻辑与运算符,但是要看使用时的具体条件来决定。
操作数1&操作数2,操作数1&&操作数2,
操作数1&操作数2,操作数1&&操作数2,
情况1:当上述的操作数是boolean类型变量时,&和&&都可以用作逻辑与运算符。
情况2:当上述的表达式结果是boolean类型变量时,&和&&都可以用作逻辑与运算符。
表示逻辑与(and),当运算符两边的表达式的结果或操作数都为true时,整个运算结果才为true,否则,只要有一方为false,结果都为false。
表示逻辑与(and),当运算符两边的表达式的结果或操作数都为true时,整个运算结果才为true,否则,只要有一方为false,结果都为false。
(1)、&逻辑运算符称为逻辑与运算符,&&逻辑运算符称为短路与运算符,也可叫逻辑与运算符。
对于&:无论任何情况,&两边的操作数或表达式都会参与计算。
对于&&:当&&左边的操作数为false或左边表达式结果为false时,&&右边的操作数或表达式将不参与计算,此时最终结果都为false。
综上所述,如果逻辑与运算的第一个操作数是false或第一个表达式的结果为false时,对于第二个操作数或表达式是否进行运算,对最终的结果没有影响,结果肯定是false。推介平时多使用&&,因为它效率更高些。
(2)、&还可以用作位运算符。当&两边操作数或两边表达式的结果不是boolean类型时,&用于按位与运算符的操作。
\d: 匹配一个数字字符。等价于[0-9]
\D: 匹配一个非数字字符。等价于[^0-9]
\s: 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]
. :匹配除换行符 \n 之外的任何单字符。要匹配 . ,请使用 \. 。
*:匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*。
+:匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+。
|:将两个匹配条件进行逻辑“或”(Or)运算
[0-9]{6}:匹配连续6个0-9之间的数字
\d+:匹配至少一个0-9之间的数字
继承(英语:inheritance)是面向对象软件技术当中的一个概念。如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”。继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。另外,为子类别追加新的属性和方法也是常见的做法。 一般静态的面向对象编程语言,继承属于静态的,意即在子类别的行为在编译期就已经决定,无法在执行期扩充。
那么如何使用继承呢?用extends关键字来继承父类。
如上面A类与B类,当写继承语句时, class A类 extends B类{ } 其中A类是子类,B类是父类。
英文 | 位置不同 | 作用不同 | |
重载 | overload | 同一个类中 | 在一个类里面为一种行为提供多种实现方式并提高可读性 现方式并提高可读性 |
重写 | override | 子类和父类间 | 父类方法无法满足子类的要求,子类通 过方法重写满足要求 |
计算机不能直接理解高级语言,只能理解和运行机器语言,所以必须要把高级语言翻译成机器语言,计算机才能运行高级语言所编写的程序。翻译的方式有两种,一个是编译,一个是解释。
用编译型语言写的程序执行之前,需要一个专门的编译过程,通过编译系统把高级语言翻译成机器语言,把源高级程序编译成为机器语言文件,比如windows下的exe文件。以后就可以直接运行而不需要编译了,因为翻译只做了一次,运行时不需要翻译,所以一般而言,编译型语言的程序执行效率高。
解释型语言在运行的时候才翻译,比如VB语言,在执行的时候,专门有一个解释器能够将VB语言翻译成机器语言,每个语句都是执行时才翻译。这样解释型语言每执行一次就要翻译一次,效率比较低。
编译型与解释型,两者各有利弊。前者由于程序执行速度快,同等条件下对系统要求较低,因此像开发操作系统、大型应用程序、数据库系统等时都采用它,像C/C++、Pascal/Object Pascal(Delphi)等都是编译语言,而一些网页脚本、服务器脚本及辅助开发接口这样的对速度要求不高、对不同系统平台间的兼容性有一定要求的程序则通常使用解释性语言,如JavaScript、VBScript、Perl、Python、Ruby、MATLAB 等等。
JAVA语言是一种编译型-解释型语言,同时具备编译特性和解释特性(其实,确切的说java就是解释型语言,其所谓的编译过程只是将.java文件编程成平台无关的字节码.class文件,并不是向C一样编译成可执行的机器语言,在此请读者注意Java中所谓的“编译”和传统的“编译”的区别)。作为编译型语言,JAVA程序要被统一编译成字节码文件——文件后缀是class。此种文件在java中又称为类文件。java类文件不能再计算机上直接执行,它需要被java虚拟机翻译成本地的机器码后才能执行,而java虚拟机的翻译过程则是解释性的。java字节码文件首先被加载到计算机内存中,然后读出一条指令,翻译一条指令,执行一条指令,该过程被称为java语言的解释执行,是由java虚拟机完成的。
1、两个变量的生命周期不同。
成员变量随着对象的创建而存在,随着对象的被回收而释放。
静态变量随着类的加载而存在,随着类的消失而消失。
2、调用方式不同。
成员变量只能被对象调用。
成员变量只能被对象调用。
成员变量只能被对象调用。
类名调用 :Person.country
3、别名不同。
成员变量也称为实例变量。
静态变量称为类变量。
4、数据存储位置不同。
成员变量数据存储在堆内存的对象中,所以也叫对象的特有数据.
静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据.
1、用final修饰的类不能被扩展,也就是说不可能有子类;
2、用final修饰的方法不能被替换或隐藏:
① 使用final修饰的实例方法在其所属类的子类中不能被替换(overridden);
② 使用final修饰的静态方法在其所属类的子类中不能被重定义(redefined)而隐藏(hidden);
3、用final修饰的变量最多只能赋值一次,在赋值方式上不同类型的变量或稍有不同:
① 静态变量必须明确赋值一次(不能只使用类型缺省值);作为类成员的静态变量,赋值可以在其声明中通过初始化表达式完成,也可以在静态初始化块中进行;作为接口成员的静态变量,赋值只能在其声明中通过初始化表达式完成;
② 实例变量同样必须明确赋值一次(不能只使用类型缺省值);赋值可以在其声明中通过初始化表达式完成,也可以在实例初始化块或构造器中进行;
③ 方法参数变量在方法被调用时创建,同时被初始化为对应实参值,终止于方法体 (body)结束,在此期间其值不能改变;
④ 构造器参数变量在构造器被调用(通过实例创建表达式或显示的构造器调用)时创建,同时被初始化,为对应实参值,终止于构造器体结束,在此期间其值不能改变;
⑤ 异常处理器参数变量在有异常被try语句的catch子句捕捉到时创建,同时被初始化为实际的异常对象,终止于catch语句块结束,在此期间其值不能改变;
⑥ 局部变量在其值被访问之前必须被明确赋值;
答:在最外层循环前加一个标记如A,然后用break A;可以跳出多重循环。(Java中支持带标签的break和continue语句,作用有点类似于C和C++中的goto语句,但是就像要避免使用goto一样,应该避免使用带标签的break和continue,因为它不会让你的程序变得更优雅,很多时候甚至有相反的作用,所以这种语法其实不知道更好)
答:方法的重载,即使返回值类型不同,也不能改变实现功能相同或类似这一既定事实;同时方法的重载只是要求两同三不同,即在同一个类中,相同的方法名称,参数列表当中的参数类型、个数、顺序不同;跟权限修饰符和返回值类无关.
答:都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。
答:静态变量是被static修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝;实例变量必须依存于某一实例,需要先创建对象然后通过对象才能访问到它,静态变量可以实现让多个对象共享内存。两者的相同点:都有默认值而且在类的任何地方都可以调用。在Java开发中,上下文类和工具类中通常会有大量的静态成员。