Java是面向对象的编程语言,不同于C语言是面向过程的。对于面向对象和面向过程的区别,举一个简单的例子说明一下(我们以洗衣机洗衣服为例):
method01()
method02()
method03()
method04()
method05()
Person
):Person
在洗衣机洗衣服这个程序任务中有三个作用,分别是打开洗衣机
、放入要洗的衣服
、放入洗衣粉
。Machine
):Machine
在洗衣机洗衣服这个程序任务中有两个作用,分别是清洗
、烘干
。从上面这个例子能看出,面向过程的编程方式比较直接且高效,而面向对象的编程方式更易复用、扩展和维护!
继承:承是Java中面向对象最显著的一个特征,继承是从已有的类中派生出新的类,新的类可以吸收已有的属性、行为,并扩展新的能力。Java中不支持多继承,但是接口可以支持多实现。
封装:将同一类事物的特征和功能包装在一起,只对外暴露需要调用的接口。封装也称为信息的隐藏,在Java中接口是体现封装最常用的方法,在接口中我们没有任何功能的实现(具体实现都交给实现类),只是定义了一系列抽象的方法声明用于外部调用。
多态:封装和继承都是为多态来服务的,多态是指同一个行为具有多个不同的表现形式。在Java中方法的重载和重写是实现多态的2种方式。
多态的三要素:继承 、重写、父类指向子类引用!
什么是编译形语言,什么又是解释形语言?
那么为什么说Java 是编译型语言呢?
第一个观点认为 Java 是编译型语言,因为Java程序想要运行,那么第一步就是要使用Javac进行编译(将Java源文件编译成.class
二进制文件)。没有经过编译的.java
文件,是没办法运行的!
那么为什么又说Java 是解释型语言呢?
那么第二个观点则是认为Java是解释型语言,Java经过编译,Javac 将.java
源文件编译成.class
二进制文件之后,仍然需要借助 JVM 的解释执行。
综合上面两个观点来看,Java似乎既有编译型语言的特点,又有解释型语言的特点,也没有看到哪本权威的书籍上认定Java就是哪一种类型的语言。
如图所示:
8种基本数据类型和取值范围:
基本类型 | 大小(位/bit) | 字节数(byte) | 最小值 | 最大值 | 默认值 | 包装器类型 |
---|---|---|---|---|---|---|
boolean | - | - | false | true | false | Boolean |
char | 16 bits | 2 bytes | Unicode 0 | Unicode 2^16-1 | 空 | Character |
byte | 8 bits | 1 byte | -2^7 | 2^7-1 | 0 | Byte |
short | 16 bits | 2 bytes | -2~15 | 2^15-1 | 0 | Short |
int | 32 bits | 4 bytes | -2^31 | 2^31-1 | 0 | Integer |
long | 64 bits | 8 bytes | -2^63 | 2^63-1 | 0 | Long |
float | 32 bits | 4 bytes | 0.0 | Fload | ||
double | 64 bits | 8 bytes | 0.0 | Double |
注意:对于boolean
值,在Java规范中并没有给出其储存大小,在《Java虚拟机规范》中给出了4个字节,和boolean
数组1个字节的定义,具体还要看虚拟机实现是否按照规范来,所以1个字节、4个字节都是有可能的。除了void之外,其他8种基本数据类型被称为八大基本数据类型。
图中从左向右的转换都是隐式转换,无需再代码中进行强制转换。从右向左均要进行强制类型转换,才能通过编译。强制转换会丢失精度。
(一) 继承方面:
(二) 成员属性方面:
public static final
修饰,这个可以省略不写;(三) 代码块方面:
(四) 构造函数方面:
(五) 方法方面:
接口在JDK1.8之后可以定义抽象方法(无方法体)、default
修饰的默认方法(有方法体)、static
修饰的静态方法(有方法体),JDK1.8以前是只能有抽象方法。
public interface Test {
static void test() {
}
default void test2(){
}
void test3();// 默认是abstract修饰
}
抽象类中除了静态方法和抽象方法外还可以有普通方法。
二者相同之处
是值传递。java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的。
java中只有值传递,基本类型传递的是值的副本,引用类型传递的是引用的副本
直接看一张图就可以理解他们的区别了:
private
,则子类就无法重写了)。List
:有序、可重复集合。按照对象插入的顺寻保存数据,允许多个Null
元素对象,可以使用iterator
迭代器遍历,也可以使用get(int index)
方法获取指定下标元素。Set
:无序、不可重复集合只允许有一个Null
元素对象,取元素时,只能使用iterator
迭代器逐一遍历。equals()
只是判断对象属性是否相同,hashCode()
要判断二者地址是否相同。java中如果要判断两个对象是否相等,需要同时满足地址 + 属性
都相同!
equals()
比较返回true
),那么它们的 hashCode
值一定要相同;hashCode
相同,它们并不一定相同;举例子:
只重写 equals()
方法,不重写 hashcode()
方法:
public class Student {
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
// 省略 get,set方法...
}
执行下面的程序看看效果:
public class hashTest {
@Test
public void test() {
Student stu1 = new Student("Jimmy",24);
Student stu2 = new Student("Jimmy",24);
System.out.println("两位同学是同一个人吗?"+stu1.equals(stu2));
System.out.println("stu1.hashCode() = "+stu1.hashCode());
System.out.println("stu1.hashCode() = "+stu2.hashCode());
}
}
如果重写了 equals()
而未重写 hashcode()
方法,可能就会出现两个没有关系的对象 equals 相同(因为equals都是根据对象的特征进行重写的),但 hashcode 不相同的情况。因为此时 Student
类的 hashcode()
方法就是 Object 默认的 hashcode()
方 法,由于默认的 hashcode()
方法是根据对象的内存地址经哈希算法得来的,所以 stu1 != stu2
,故两者的 hashcode 值不一定相等。
根据 hashcode 的规则,两个对象相等其 hash 值一定要相等,矛盾就这样产生了。上面我们已经解释了为什么要使用 hashcode 算法,所以即使字面量相等,但是产生两个不同的 hashCode 值显然不是我们想要的结果。
如果我们在重写 equals() 时,也重写了 hashCode() 方法:
public class Student {
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
// 省略 get,set方法...
}
再来看执行结果:
两位同学是同一个人吗?true
stu1.hashCode() = 71578563
stu1.hashCode() = 71578563
从 Student
类重写后的 hashcode()
方法中可以看出,重写后返回的新的 hash 值与 Student
的两个属性是有关,这样就确保了对象和对象地址之间的关联性。
如果文章帮助您复习巩固了知识点,三连支持一下,后续会亿点点的更新!