初学者,经常听到JDK、JRE这些名词,简单地说,JRE就是运行java字节码的虚拟机。但是,如果只有java源码,要编译成java字节码,就需要JDK,因为JDK包含了JRE,还提供了编译器、调试器等开发工具。
java三个不同的版本:java SE、java EE、java ME。
简单来说,Java SE就是标准版,包含标准的JVM和标准库,而Java EE是企业版,它只是在Java SE的基础上加上了大量的API和库,以便方便开发Web应用、数据库、消息服务等,Java EE的应用使用的虚拟机和Java SE完全相同。
毫无疑问,Java SE是整个Java平台的核心,而Java EE是进一步学习Web应用所必须的。
java版本:从1995年发布1.0版本开始,到目前为止,最新的Java版本是Java 13。
基础小结:一个Java源码只能定义一个
public
类型的class,并且class名称和文件名要完全一致;使用
javac
可以将.java
源码编译成.class
字节码;使用
java
可以运行一个已编译的Java程序,参数是类名。
Java的三个特性:封装、继承、多态。
一、封装
- 面向对象编程的核心思想之一就是将数据和对数据的操作封装在一起。通过抽象,即从具体的实例中抽取出共同的性质形成一般的概念,例如类的概念。
- 是指隐藏对象的属性和实现细节,仅对外提供公共的访问方式。
- 好处: (1)隐藏实现细节,提供公共访问方式;
(2)提高代码的复用性;
(3)提高代码的安全性。 - private关键字
- (1)私有的意义,可以修饰成员变量和成员方法。
(2)被private修饰的成员只能在本类中被访问。
(3)把成员变量用private修饰,提供对应的getxxx()方法和setXxx()方法 this关键字 - (1)代表当前类的引用对象;(那个对象调用方法,该方法内部的this就代表那个对象)
(2)解决了局部变量隐藏成员变量的问题、 构造方法 (1)用于对对象的数据进行初始化。
(2)格式:方法名和类名相同;没有返回值类型(void也没有);没有返回值。
(3)如果我们没有写构造方法,系统将提供一个默认的无参构造方法;
class Test{
//系统提供的无参构造方法
public Test() {
}
}
(4)如果我们给出了构造方法,系统将不再提供默认构造方法。(推荐自己给出)
(5)给成员变量赋值的方式(两种):
带参构造:
public Phone() {
}
//见名知意
public Phone(String brand,int price) {
this.brand = brand;
this.price = price;
}
steXxx():
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
(6)代码Student s = new Student();做了哪些事情?
把Student.class文件加载到内存;
在栈内为s开辟空间;
在堆内为Student对象申请空间;
给学生的成员变量进行初始化;(String—null ,int—0)
给学生的成员变量显示初始化;
通过构造方法给成员变量进行初始化;
对象构造完毕,把地址赋值给s变量。
- static关键字 (1)静态的意思,可以修饰成员变量和成员方法;
(2)static的特点
①随着类的加载而加载;
②优先于对象存在;
③被类的多有对象共享;
④既可以通过对象名调用,也可以通过类名调用;
⑤静态的内容在方法区的静态区。
(3)在静态方法中没有this对象;静态只能访问静态。
(4)静态变量和成员变量的区别
①所属不同:静态变量属于类,类变量;成员变量属于对象,对象变量,实例变量。
②内存位置不同:静态变量在方法区的静态区;成员变量在推内存。
③生命周期不同:静态变量随着类的加载而加载,随着类的消失而消失;成员变量随着对象的创建而存在,随着对象 的消失而消失。
④调用不同:静态变量既可以通过对象调用,也可以通过类名调用;成员变量只能通过对象调用。 - main方法 (1)main方法是静态的。
(2)public static void main(String[] args)
public:公共的,访问权限是最大的。由于main方法是被JVM调用,所以权限要足够大。
static:静态的,不需要创建对象,通过类名就可以被调用,方便JVM调用。
void:返回值给JVM,没有意义
main:就是一个常见的名称
String[] args:可以接收数据,提供程序的灵活性
一个学生类 :
class Student {
//学生姓名
private String name;
//学生年龄
private int age;
//构造方法
public Student() {
}
public Student(String name,int age) {
this.name = name;
this.age = age;
}
//getXxx() 和 setXxx()
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;
}
//show方法(输出成员变量)
public void show() {
System.out.println(name+"---"+age);
}
}
//测试类
public class Demo{
public static void main(String[] args) {
//方法一
//创建对象
Student s1 = new Student();
s1.setName("肖战");
s1.setAge(27);
//输出结果
System.out.println(s1.getName()+"---"+s1.getAge());
s1.show();
//方法二
Student s2 = new Student("王一博",21);
System.out.println(s2.getName()+"---"+s2.getAge());
}
}
代码块{}:
(1)根据位置和声明的不同,可分为局部代码块和构造代码块;
(2)执行顺序:静态(只执行一次)→构造代码块→构造方法;
(3)静态代码块随着类的加载而加载,子类在初始化之前,会先进行父类的初始化。
二、继承
继承是面向对象编程的一种强大的代码复用方式;
Java只允许单继承,所有类最终的根类是Object;
protected允许子类访问父类的字段和方法;
子类的构造方法可以通过super()调用父类的构造方法;
可以安全地向上转型为更抽象的类型;
可以强制向下转型,最好借助instanceof判断;
子类和父类的关系是is,has关系不能用继承。
- 把多个类中相同的成员提取出来,定义到一个独立的类中。然后让多个类与这个独立的类产生一个关系,这多个类就具备了这些内容。这个关系叫继承。(多各类中存在相同的属性和行为时,将这些内容抽取到单独的一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可)
- 继承的好处: (1)提高了代码的复用性;
(2)提高了代码的维护性;
(3)让类与类产生了一个关系,是多态的前提。 - 继承的弊端: (1)让类的耦合性增强,这样某个类的改变就会影响其他与该类相关和类;
(开发的原则:低耦合,高内聚。耦合:类与类的关系,内聚:自己完成某件事情的能力)
(2)打破了封装性。 - Java中继承的特点: (1)Java中类只支持单继承;
(2)Java中可以多层继承(继承体系) - 继承的注意事项: (1)子类不能继承父类的私有成员;
(2)子类不能继承父类的构造方法,但可以通过super去访问;
(3)不要为了部分功能而去继承(自行体会)。 - 关键字extends (1)Java中用关键字extends表示继承;
(2)格式:class 子类名 extends 父类名 { }。 - 关键字super 与this相似,它可以直接访问父类的数据。
this与super 的区别
(1)this代表本类对象的引用 ;父类代表存储空间的标识(可以理解为父类的引用,可以操作父类的成员)
(2)用法
A. 调用成员变量:this.成员变量(调用本类的成员变量);super.成员变量(调用父类的成员变量);
B. 调用构造方法:this(…);super(…)
C. 调用成员方法:this.成员方法;super.成员方法。
方法重载和方法重写的区别(Override和Overload)
(1)方法重写:在子类中出现和父类相同的方法声明的现象。
(2)方法重载:同一个类中,出现的方法名相同,参数列表不同的现象。
(3)方法重载能改变返回值的类型,因为他和返回值类型无关。 - 关键字final final:最终的意思,由于继承中有一个现象-方法重写,所以,父类的功能就会被子类给覆盖掉。有些时候我们不想让子类去覆盖父类的功能,针对这种情况,Java就提供了一个关键字final。
final可以修饰类,方法和变量:
(1)修饰类:该类不能被继承;
(2)修饰方法:该方法不能被重写;
(3)修饰变量:该变量不能被重新赋值。(因为被修饰的变量此时其实是常量)
拓展:常量包括字面常量和自定义常量(final int x = 10;)。
final修饰局部变量:
(1)局部变量是基本类型:基本类型的值不能被改变;
(2)局部变量是引用类型:引用类型的地址值不能被改变,但是,该对象的堆内存的值是可以改变的。
final修饰变量的初始化时机:被final修饰的变量只能赋值一次。
三、多态
在继承关系中,子类如果定义了一个与父类方法签名完全相同的方法,被称为重写(Override)。
多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法。
- 同一个对象在不同时刻体现出来的不同状态。
- 多态的前提: (1)有继承或者实现关系;
(2)有方法重写;
(3)有父类或者父类接口引用指向子类对象。 - 多态的分类: (1)具体类多态:
class Fu{
}
class Zi extends Fu{
}
Fu f new Zi();
(2)抽象类多态:
abstract class Fu{
}
class Zi extends Fu{
}
Fu f new Zi();
(3)接口多态:
interface Fu{
}
class Zi implements Fu{
}
Fu f = new Zi();
- 多态中成员访问特点: (1)成员变量:编译看左边,运行看左边;(这里的左右是说的创建对象时等号的左右)
(2)构造方法:创建子类对象时,访问父类的构造方法,对父类的数据进行初始化(子类构造都会默认访问父类构造)
(3)成员方法:编译看左边,运行看右边;
(4)静态方法:编译看左边,运行看左边。
(5)原因:因为只有成员方法存在方法重写。静态和类相关,算不上重写,所以访问的还是左边的。 - 多态的好处: (1)提高代码的维护性(继承保证或体现);
(2)提高代码的扩展性(多态体现)。 - 多态的弊端:父不能使用子的特有供能。
- 多态中的转型 (1)向上转型:从子到父;
(2)向下转型:从父到子。
Fu f = new Zi();
Zi z = (Zi)f;
- 抽象类:把多个共性的东西提取到一个类中,这是继承的做法,但是这多个共性的东西,有些时候方法声明一样,可能方法体不一样。也就是说方法声明一样,但是每个具体的对象在具体实现的内容不一样,所以我们在定义这些共性的方法的时候,就不能给出具体的方法体。 而一个没有具体的方法体的方法是抽象的方法。在一个类中如果有抽象方法,该类必须定义为抽象类。
- 如果一个class定义了方法,但没有具体执行代码,这个方法就是抽象方法,抽象方法用abstract修饰。因为无法执行抽象方法,因此这个类也必须申明为抽象类(abstract class)。使用abstract修饰的类就是抽象类。我们无法实例化一个抽象类:
Person p = new Person(); // 编译错误
无法实例化的抽象类有什么用?
因为抽象类本身被设计成只能用于被继承,因此,抽象类可以强迫子类实现其定义的抽象方法,否则编译会报错。因此,抽象方法实际上相当于定义了“规范”。
- 关键字abstract 抽象类的格式:
abstract class 类名{
//抽象方法
public abstract void 方法名();
}
抽象类的特点:
(1)抽象类和抽象方法必须用关键字abstract修饰;
(2)抽象类中不一定有抽象方法,但有抽象方法的类一定是抽象类;
(3)抽象类不能事例化;
(4)抽象类的子类:
A. 是一个抽象类;
B. 是一个具体类:这个类必须重写抽象类中的所有抽象方法。
抽象类中的成员特点:
(1)成员变量:有变量,有常量;
(2)构造方法:有构造方法;(但不能实例化,作用:用于子类访问父类数据的初始化)
(3)成员方法:有抽象方法(强制要求子类做的事情),有非抽象方法(子类继承的事情,提高代码的复用性)。
抽象类的几个小问题
(1)一个类如果没有抽象方法,却还是定义为抽象类的意义:为了不让创建对象;
(2)abstract 不能与final(冲突)private(冲突)和static(无意义)共存。
猫狗抽象类案例:
/*
* 抽象类
* 猫狗案例
*/
//抽象动物类
abstract class Animall{
//姓名、年龄
private String name;
private int age;
//构造方法(无参和带参)
public Animall() {
}
public Animall(String name,int age) {
this.name = name;
this.age = age;
}
//getXxx()
public String getName() {
return name;
}
public int getAge() {
return age;
}
//定义一个抽象方法
public abstract void eat();
}
//猫类
class Catt extends Animall{
public Catt() {
}
public Catt(String name,int age) {
super(name,age);
}
public void eat() {
System.out.println("它喜欢吃鱼");
}
}
//狗类
class Dogg extends Animall{
public Dogg() {
}
public Dogg(String name,int age) {
super(name,age);
}
public void eat() {
System.out.println("它喜欢啃骨头");
}
}
//测试类
public class Test2 {
public static void main(String[] args) {
//测试猫类
Animall a = new Catt("球球",1);
System.out.println(a.getName()+"今年"+a.getAge()+"岁啦");
a.eat();
//测试狗类
a = new Dogg("旺财",2);
System.out.println(a.getName()+"今年"+a.getAge()+"岁啦");
a.eat();
}
}
通过abstract定义的方法是抽象方法,它只有定义,没有实现。抽象方法定义了子类必须实现的接口规范;
定义了抽象方法的class必须被定义为抽象类,从抽象类继承的子类必须实现抽象方法;
如果不实现抽象方法,则该子类仍是一个抽象类;
面向抽象编程使得调用者只关心抽象方法的定义,不关心子类的具体实现。
四、接口
在抽象类中,抽象方法本质上是定义接口规范:即规定高层类的接口,从而保证所有子类都有相同的接口实现,这样,多态就能发挥出威力。
如果一个抽象类没有字段,所有方法全部都是抽象方法,就可以把该抽象类改写为接口:
interface
。所谓
interface
,就是比抽象类还要抽象的纯抽象接口,因为它连字段都不能有。因为接口定义的所有方法默认都是public abstract
的,所以这两个修饰符不需要写出来(写不写效果都一样)。当一个具体的
class
去实现一个interface
时,需要使用implements
关键字。我们知道,在Java中,一个类只能继承自另一个类,不能从多个类继承。但是,一个类可以实现多个
interface
,例如:class Student implements Person, Hello { // 实现了两个interface ... }
实现类可以不必覆写
default
方法。default
方法的目的是,当我们需要给接口新增一个方法时,会涉及到修改全部子类。如果新增的是default
方法,那么子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法。
- 一个类通过继承接口的方式,从而来继承接口的抽象方法。 接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。(举例解释:比如说猫钻火圈,狗跳高等功能,不是动物本身就具有的,是在之后被训练出来的,这种额外的供能,java提供了接口表示)
- 接口的特点: (1)接口用关键字interface修饰,各式:interface 接口名 {};
(2)接口不能实例化;
(3)接口的实现类:
A. 是一个抽象类;
B. 是一个具体类,这个类必须重写接口中的所有抽象方法。 - 接口的成员特点: (1)成员变量:只能是常量,默认修饰符:public static final ;
(2)构造方法:无构造方法;
(3)成员方法:只能是抽象的,默认修饰符 public abstract. - 类与类,类与接口,接口与接口 (1)类与类:继承关系,只能单继承,可以多层继承;
(2)类与接口:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现一个接口;
格式:class 类名 implements 接口名{ }
(3)接口与接口:继承关系,可以单继承,也可以多继承。 - 抽象类与接口的区别: (1)成员区别:……
(2)关系区别:……
(3)设计理念不同:
A. 抽象类中定义的是共性功能;
B. 接口定义的是扩展功能 - 接口案例
/*
* 接口
* 老师和学生案例,加入打游戏的另外功能
* 分析:从具体到抽象
* 老师:姓名,年龄,吃饭,睡觉
* 学生:姓名,年龄,吃饭,睡觉
* 由于有共性功能,所以我们可以提取出一个父类,定义为人类。
* 人类:姓名,年龄
* 吃饭();//抽象
* 睡觉(){}
* 打游戏的另外功能并不是所有老师和学生一开始都具备的,所以我们把它定义为接口。
* 打游戏接口:
* 部分老师打游戏:实现打游戏接口;
* 部分学生打游戏:实现打游戏接口
* 实现:从抽象到具体
* 使用:具体
*/
//人类
abstract class Human{
//姓名,年龄
private String name;
private int age;
//构造方法
public Human() {
}
public Human(String name,int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
//吃饭
public abstract void eat();
//睡觉
public void sellp() {
System.out.println("喜欢睡觉");
}
}
//定义打游戏接口
interface PlayGame{
//打游戏的抽象方法
public abstract void game();
}
//教师类
class Teacher extends Human {
public Teacher() {
}
public Teacher(String name,int age) {
super(name,age);
}
public void eat() {
System.out.println("喜欢吃红烧肉");
}
}
//学生类
class Student extends Human {
public Student() {
}
public Student(String name,int age) {
super(name,age);
}
public void eat() {
System.out.println("喜欢吃红烧狮子头");
}
}
//打游戏的老师
class PlayGameT extends Teacher implements PlayGame {
public PlayGameT() {
}
public PlayGameT(String name,int age) {
super(name,age);
}
public void game() {
System.out.println("喜欢打游戏");
}
}
//打游戏的学生
class PlayGameS extends Student implements PlayGame {
public PlayGameS() {
}
public PlayGameS(String name,int age) {
super(name,age);
}
public void game() {
System.out.println("喜欢打游戏");
}
}
//测试类
public class Test3 {
public static void main(String[] args) {
//教师
PlayGameT t = new PlayGameT("马云",30);
System.out.println(t.getName()+"今年"+t.getAge());
t.eat();
t.sellp();
t.game();
//学生
PlayGameS s = new PlayGameS("马化腾",20);
System.out.println(s.getName()+"今年"+s.getAge());
s.eat();
s.sellp();
s.game();
}
}