面向对象是一种更为优秀的程序设计方法,它的基本思想是使用类、对象、继承、封装、消息等基本概念进行程序设计。
封装:将对象的实现细节封装起来,然后通过一些公用的方法来暴露该对象的功能。
继承:是面向对象实现软件复用的重要手段,子类继承父类,子类将直接获得父类的属性和方法。
多态:子类对象可以直接赋给父类变量,但是在运行时依然表现出子类的行为特征,这意味着同一个类型的对象在执行同一个方法时,可能表现出多重行为特征。
类是对象的抽象,而对象是类的实例。对一个类的定义而言,包含了三种最常见的成员:构造器、成员变量和方法。
static 是一个特殊的关键字,可以用于修饰方法和成员变量,被static修饰表明属于类本身,而不属于该类的单个实例,因此成为类变量和类方法,而实例方法与其不同,访问该类的成员和方法不受限制。
UML(统一建模语言)
面向对象软件开发需要经过OOA(面向对象分析)、OOD(面向对象设计)和OOP(面向对象编程)的三个阶段。
Java语言支持的类型分类:基本类型和引用类型。
整数类型:byte(1个字节)、short(两个字节)、int(4个字节)和long(8个字节)
字符类型:char(2个字节)
浮点类型:float(4个字节)、double(8个字节)
布尔类型:boolean
整数值的4种表示方式:0b或0B表示二进制、o表示八进制、0x或者oX表示十六进制。
整数值默认是int,占32位,例如0b11101001,如果加L或者l,这个二进制默认占64位。
字符型值也可以用十六进制表示,范围是'\u0000'~'uFFFF',和ASCII码中的字符完全重合。
负数在计算机中以补码的形式出现。
浮点类型默认是double类型。
类型的强制转换和表达式自动提升。强制转换,右边的范围一般高于左边。自动提升注意赋值的左右两边类型一致,否则报错。
++:自加(自减)
如果把++放在左边,则先把操作数加1,再把操作数放入表达式中运算,如果++放在右边,则先把操作数放入表达式运算,在把操作数加1。
<<:左移运算符
>>:右移运算符,左边空出来,负数补1,整数补0。即以符号位填充。
>>>:无符号右移运算符,左边空出来的总是补0。
对低于int类型的数据,先转换为int类型,再进行移位。对于移位大于被移位数据类型时,要进行先求余,再移位。
break、continue、return、foreach用法。
2.引用类型
数组是一种引用数据类型,数组元素和数组变量在内存里是分开存放的。数组引用变量只是一个引用,这个引用可以指向有效内存的任何地方。实际数组对象存储在堆内存中,引用该数组的变量是一个局部变量,存储在栈内存中。
当一个方法被调用时,每个方法就会建立自己的内存栈,在这个方法内定义的变量将被逐个放入该内存中,随着方法的结束,这个方法的内存也就销毁了,而在程序中创建一个对象时,这个对象就会被放在堆内存中,以便反复利用,即使方法结束对内存的对象也不会内销毁,有可能被另一个引用变量引用,除非没有其他引用,Java虚拟机的垃圾回收机制在合适的时候自动回收该对象。
对象的this引用:对象的一个方法依赖(调用)于另一个方法的情形。大部分时候,一个方法访问该类中的其他方法、成员变量时,可以省略this,效果是一样的。但是,对于static修饰的方法而言,使用this无法指向合适的对象,所以被static修饰的方法不能够访问非静态的成员。因此Java语法规定:静态成员不能够访问非静态成员。
尽可能使用类名调用静态方法,因为该静态方法是属于类的,不属于该类的实例。
方法的理解
Java里的方法不能够独立存在,调用方法必须使用类或者对象。
参数传递的机制:基本类型和引用类型的参数传递。基本类型情况下,就是将实际参数复制到传入的方法中,参数本身不受影响;而引用类型传递的引用变量给形参,实参和形参同时指向同一个对象,通过形参改变对象的值,实参所指向的对象也将改变。
递归方法的一个重要原则:递归一定要向已知的方向递归。
重载: 发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。
成员变量包括:实例变量和类变量,类变量的范围大于实例变量的范围,同一个类的所有实例访问类变量时,实际上访问的是该类同一片内存区域的一个变量。
class Person{
//实例变量
public String name;
//类变量
public static int eyeNum;
}
//创建第一个Person对象
Person p1 = new Person();
//创建第二个Person对象
Person p2 = new Person();
//分别给两个对象的name实例变量赋值
p1.neme = "张三";
p2.name = "孙悟空";
//分别给两个Person对象的eyeNum类变量赋值
p1.eyeNum = 2;
p2.eyeNum = 3;
局部变量包括:形参、方法局部变量和代码块局部变量。
访问代码块局部变量之前必须初始化,否则出错。离开了代码块局部变量所在的代码块,这个局部变量也就被销毁了。
局部变量会覆盖成员变量,成员变量依然可以使用this和类名来调用。
类加载器先初始化类,然后创建实例,eyeNum是属于类的,并不属于Person对象,创建第一个实例对象时,系统并不需要为eyeNum分配内存,只是为实例变量name分配了内存。如果再创建第二个Person对象,不需要对Perso类进行初始化。
与成员变量不同的是,局部变量不属于任何类和实例,因此它总是保存在其所在方法的栈内存中,基本类型的变量保存的是值,引用类型的变量保存的是地址。
使用import可以省略写包名,使用static import则可以连类名就能省略。
构造器初始化,构造器重载
例如使用this(name.color)调用另一个构造器的初始化代码。
重写父类的方法,父类private方法不能够子类重写(覆盖),该方法对其子类是隐藏的。
重写:“两同两小一大原则” ,发生在父子类中,方法名、参数列表必须相同,返回值范围小于等于父类,抛出的异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类方法访问修饰符为 private 则子类就不能重写该方法。
super调用父类被覆盖的方法,调用父类的变量和方法。子类实例变量名和父类实例变量名相同,子类会隐藏父类的实例变量。可以使用super.变量访问父类的实例变量。
如果在某个方法中访问变量a,(1)先查找该方法中是否有局部变量(2)查找当前类是否有该成员(3)查找直接父类是否有该成员变量,进而追溯上一级的父类,知道找到该变量,否则编译错误。
调用父类的构造器super(name,color),子类构造器调用父类构造器时,super语句必须放在子类构造器的第一行。
创建任何一个java对象时,最先执行的Object类的构造器。执行原则:从该类所在继承树最顶层类的构造器开始执行。
如果编译时类型和运行时类型不一致,当运行时调用该变量的方法时,其方法行为总能够表现出子类方法的行为特征,而不是父类方法的行为特征,这就是传说中的多态。另外注意一条原则:编译看左边,运行看右边。
在开发中首先使用instanceof运算符判断是否具备该类的特性,然后用(type)强制转换,增加了程序的健壮性,而且不会出现错误。
都能够实现类的复用手段,但是继承会破会封装,组合提供更好地封装,组合很常见啊,Spring中注入bean,就是组合。
这是在笔试题中经常遇到的问题,java类四个成员,成员变量,方法,构造器和初始化块。
初始化代码块的修饰符只能是static,称为静态代码块。
先执行实例变量的赋值,再执行代码块的赋值。
先执行代码块,再执行构造器。
静态代码块不管顺序如何,都会在main函数之前执行。
Java初始化的顺序:父类静态变量-->父类静态代码块-->子类静态变量-->子类静态代码块-->父类非静态变量-->父类菲静态代码块-->父类构造函数-->子类非静态变量-->子类菲静态代码块-->子类构造函数
普通初始化块、声明实例变量指的默认值都可认为对象的初始化代码,它们执行的顺序和源程序的顺利一致。
public class Demo1 {
{
a = 6;
System.out.println("a = 6;");
}
int a = 9;
public static void main(String[] args){
System.out.println(new Demo1().a);
}
}
public class Demo1 {
int a = 9;
{
a = 6;
System.out.println("a = 6;");
}
public static void main(String[] args){
System.out.println(new Demo1().a);
}
}
静态初始化块、声明静态成员变量指的初始值可认为是该类的初始化代码,它们执行的顺序和源程序的顺利一致。
public class Demo1 {
static {
a = 6;
System.out.println("a = 6;");
}
static int a = 9;
public static void main(String[] args){
System.out.println(new Demo1().a);
}
}
public class Demo1 {
static int a = 9;
static {
a = 6;
System.out.println("a = 6;");
}
public static void main(String[] args){
System.out.println(new Demo1().a);
}
}
parseXxx(String s) String.valueOf(基本类型)
package com.quan.sort.fastsort;
public class Demo1 {
public static void main(String[] args) {
Person p = new Person("zhangsan");
System.out.println(p);
System.out.println(p.toString());
}
}
class Person{
String name;
Person(String name){
this.name = name;
}
}
结果:类全名+@+十六机制的哈希值
为什么是这样的格式???com.quan.sort.fastsort.Person@1540e19d
Person继承了Object类的toString方法。源码分析:
如果比较的是两个基本类型的值,只要值相同就返回true。引用类型的比较,必须指向同一个对象才能够返回true。
"abc"和new String("abc")的区别?"abc"编译时就计算出来的字符串值,JVM将会使用常量池管理这些字符串。而是用new String("abc")时,JVM将会使用常量池管理这个直接量,然后再调用String类的构造器创建一个新的String对象,新创建的String对象放在堆内存中。换句话说,new String("abc")一共产生了两个字符串对象。
JVM常量池保证相同的字符串只有一个,不会出现副本。
String类中的equals方法比较的是引用变量所指对象的值相等,就会返回true,因为重写了Object的equals方法。
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
严格上说equals方法,是具体的实现,想怎么相等就怎么相等。全部自己做主。
final变量:被final修饰的基本类型的变量只能赋值一次,不能够再次改变被final修饰的引用变量不能够被重新赋值,但是引用变量所指对象的值可以改变。
final方法:被final修饰的方法不能够被重写,但是可以被重载。
final类:不可以有子类,保证不被继承。
Integer的缓存范围为-128~127.
Integer in1 = new Integer(6);
//创建一个新的对象,并缓存该对象
Integer in2 = Integer.valueOf(6);
//直接冲缓存中取出该对象
Integer in3 = Integer.valueOf(6);
System.out.println(in1 == in2);
System.out.println(in3 == in2);