介绍
1.Java是一个面向对象的程序设计语言
面向对象的三大特征:①封装性 ②继承性 ③多态性
继承性:在继承父类的前提下扩展更多的功能
eg.
class Person{//父类
int age;
String name;
void sayHello(){...}
}
class Student extends Person{//子类
String school;
double score;
void meetTeacher(){...}
}
2.对象:在计算机中是一个可标识的存储区域
3.类(class):这一类对象具有的共同的属性和行为的集合
类的构成:
①属性:变量(字段field)
②行为:函数(方法method)
4.类和对象的关系:
类是对象的抽象(模版)
对象是类的实例
eg.
这是一个类
public class Person{
int age;//变量
String name;
public void sayHello(){//函数
System.out.println("Hello");
}
}
这是一个对象
Person p = new Person();
程序的编辑,编译与运行
1. 编辑
用任意文本编辑器(记事本,sublime,vscode,vi,IDE(Integrated Development Environment综合编译环境)等等),编辑出来的就是一个 .java文件
2. 编译
将.java文件转变成字节码文件(.class文件),这个过程是利用JDK(Java Development Kit)中的javac.exe(C就是compile编译的意思)来实现的
3. 运行
通过JRE(Java Runtime Environment)里面的java.exe读入并解释字节码文件(.class),最终.class文件会在在JVM(Java Virtual Machine)上运行
JDK,JRE,JVM三者关系:
JDK包含了JRE,JDK侧重于Java 程序的编译,JRE侧重于Java程序的运行,在JRE运行时,里面会自动产生一个JVM
编码标准
- 类名首字母大写,后面单词驼峰
- 方法名和变量名首字母小写,后面单词驼峰
Java类结构和main函数
Java类结构
- 类名和文件名相同,且一个Java文件只能有一个 public class
public class test//文件名必须命名为test
- 一个文件可以有多个class(但不提倡),但只能有一个public class(这里是文件名)
- System.out.print 输出
System.out.println 换行输出 - Java中所有内容都要放在类中,因此Java项目就是由一个个类组成
- 类的构成:
①属性:变量(字段field)
②行为:函数(方法method) - 一个Java程序可以调用多个其他Java class,使用(import)
public class Person{
int age;//成员变量 member variables
String name;
//不允许在这里写System.out.println("Hello");
public void sayHello(){//成员函数 member functions
System.out.println("Hello");
}
}
//不允许在这里写System.out.println("Hello");
main函数
- 一个class只能有一个main函数。main函数是主动执行呢个的函数,是Java程序的总入口(和c一样)
- 没有main函数的类不能主动执行,但可以通过调用执行(类似调用函数)
- main函数写法固定为
简单记忆:PSVM
public static void main(String[] args){...}
- main函数不属于这个类的所拥有函数(成员函数),他只是寄居在某个class中
- main函数无法被其他方法和类调用
基本类型
- boolean 布尔
boolean a=true;
- byte 字节
1byte = 8bit
存储有符号的,以二进制补码表示的整数
范围:-128~127
默认值:0
使用:在大型数组中用来代替小整数可以显著节约空间,因为4*sizeof(byte)=sizeof(int)
在二进制文件中使用较多
byte a=(byte)-128;
System.out.println(a);//-128
- short/int/long
short 最大32767;
int 最大记住2 000 000 000就行,2后面9个0;
long 超过int必须加L,没有超过虽然不会报错,但也会自动进行类型转换,所以还是都在数字后面加上L
long a = 1000L;
- float/double
float 数据后面必加f
float a = 1.23f;
double 数据后面可以加d,也可以不加
- char
注意,Java的char类型占2个字节,因为Java中为了很好的显示汉字,而汉字占2个字节;当然数字和字母还是占1个字节
‘\u4e00’~’\u9fa5’ 表示两万多个汉字(\u+4个字符)
自定义函数
注意:
- 函数必须放在类的范围内
- 格式:
修饰词(public 或static) 返回值(int或void) 函数名(形参列表){
//函数体
}
- 通常情况下,建议方法是pubic,容易调用
- 重载函数(overload):
函数名称相同,但是函数参数的个数或类型必须有所不同。但不能以返回值来区分同名的函数。
换句话说,只要函数名相同,形参列表也相同,这两个函数就是相同的函数。
public class test{
public static void main(String[] args) {
int a=1,b=2;
System.out.println(add(1,2));
System.out.println(add(1.5,2.5));
}
//这两个是两个不同的函数,根据参数类型不同,自动分开调用
public static int add (int m,int n){
return m+m;
}
public static double add(double m,double n){
return m+n;
}
}
面向对象思想
对象 = 属性 + 方法
对象的规范 = 属性定义 + 方法定义
-
对象和类
对象是一个变量(具体的东西)
类就是类型(是规范,是定义)
类规定了对象应有的属性内容和方法;
对象是类的具体实现,是活生生的;
例如:一个人是对象,人类是类 -
变量定义的变迁:更加功能强大
基本类型 (一种变量) ==》 结构体(多种变量捆绑) ==》类(多种变量+方法) -
类可以继承
子类可以继承父类的所有功能(不能直接访问priva成员) -
面向对象语言的主要特点
①识认性(辨识,认定)
②类别性
③多态性
④继承性
Java类和对象
-
最简单的类:
class A{} -
对象:
A obj = new A();
类型 变量名 = new 类型 (参数); -
A obj = new A();
obj 可以看作是内存中的一个对象(包括若干个数据)的句柄
在C/C++中,obj称为指针(变量名);在Java中成为reference(参考),实际上本质上也是一个指针
对象赋值是reference赋值,而基本类型是直接拷贝
注意:因为句柄本质上是一个指针,因此在函数传参时,不需要使用指针传递地址,可直接使用句柄。
- new出一个对象后,内部属性是有默认值的:
short = 0; int = 0; long = 0L;
boolean = false;
char = ‘\u0000’;(空格)
byte = 0;
float = 0.0f;
double = 0.0d;
构造函数(construction function)
可以在对象创建的时候就给成员变量赋值
eg.
public class A{
int id;
public A(int id2){//这就是构造函数
id = id2;
}
}
A obj = new A(10);
-
名称必须和类名一样
-
没有返回值(不能写void,如果写public void A(int id2){…}这就不是构造函数,而是普通函数)
-
Java有构造函数,但没有析构函数
在每个变量(对象)创建的时候,将调用构造函数,为该变量分配内存;当变量(对象)的生命周期结束,析构函数将回收这块内存,以便分配给其他变量。
但Java有自动回收机制,当变量的生命周期结束,JVM会自动回收所分配的对象的内存。 -
每个Java类都必须有构造函数
如果没有显式定义构造函数,Java编译器会自动为该类产生一个空的无形参构造函数:
class A{}
//编译器将会自动生成:
class A{
public A(){}//空的无形参构造函数
}
-
一个类可以有多个构造函数,只要形参列表不相同即可(类似重构函数)
在new对象的时候,会根据实参的不同,自动挑选不同的构造函数。如果实参和形参匹配不上,将会报错 -
子类的构造函数的第一句话都默认调用父类的无参数构造函数
信息隐藏原则
-
面向对象有一个法则:信息隐藏
类的成员属性是私有的:private;
类的方法是公有的:public;
所以我们通常使用类的方法来访问类的属性,而不是直接访问类的属性 -
get和set方法可以对类的属性进行操作,而Java的IDEA可以快速生成这两个方法:
idea的生成方法:右键 -> Generate(快捷键alt+insert) -> 选择要生成的属性 ->确认
this
this就相当于这个类本身,可以把他看成类名的替代
eg.
public class TEST {
private int height;
private int weight;
private int age;
private String name;
public void setHeight(int height) {
this.height = height;//这里this指代这个类本身
}
}
用法:
- 指向本类中的成员变量
- 指向本类中的成员方法
- 可以当作构造函数使用
继承
-
类别内的对象和方法都具有一定的共同点,将共同点提取出来,就形成了父类/基类/超类
Parent class/Base class/Super class -
而0其他类自动成为子类/派生类
Child class/Derived class -
同样的方法名和参数的情况下,本类的方法比父类方法优先级高
-
单根继承原则:每个类只能继承一个类
如果不写extends,Java类都会默认继承java.lang.Object类
所有类从java.lang.Object开始,构建出一个类型继承树(不会出现方法指代不清的情况) -
java.lang.Object类里面默认就有clone,equals,finalize,getClass,hashCode,toString等方法
-
每个子类的构造函数的第一句话,都默认调用父类的无参数构造函数super(),除非子类的构造函数第一句话树super,而却super语句必须放在第一条!!!不会出现连续两条super语句
注:super()的功能就是调用父类的无参数构造函数
抽象类
首先,一个完整健康的类中,所有的方法的都有实现(都有方法体)
完整的方法:
方法名(参数)
{
方法体
}
抽象类:该类存在有方法只有方法名、形参列表,没有方法体
eg.
public abstract class Shape//抽象类abstract的声明
{
int area;
public abstract void calArea();//方法也要声明
}
抽象类的性质:
- 抽象类需要声明:abstract class
- 抽象类也是类。子类可以继承于抽象类。
- 如果子类继承于抽象类,要想变成完整类,必须要把父类的所有抽象方法实现;否则必须被定义为抽象类。
- 抽象类是无法被实例化,不能new操作的!!!
- 抽象类有构造函数,可以有main,可以有private/protected
eg.
父类:
public abstract class Shape{//定义一个抽象类
int area;//面积
public abstract void calArea();//计算面积的抽象方法
}
子类:
public class Rectangle extends Shape{
int width;
int length;
public Rectangle(int length,int width)//构造函数
{
this.length = length;
this.width = width;
}
public void calArea()//要将父类的抽象方法实现,此时就不用声明abstract
{
System.out.println(this.length * this.width);
}
//main函数
public static void main(String[] args)
{
Rectangle rect = new Rectangle(10,5);
rect.calArea();
}
}
接口
如果类的所有方法都没有实现,那么这个类就算是接口(interface)
eg.
public interface Animal//接口需要声明
{
public void eat();
public void move();
}
接口的性质:
-
接口必须声明:interface
-
接口不算类,所以不用在interface后面写class,接口可以继承多个接口,类可以实现多个接口。
-
类可以同时继承(extends)一个类并且实现(implements)多个接口,但是extends必须放在implements前面
-
接口里可以定义变量,但一般是常量
-
接口也不能被实例化,不能new操作
-
接口没有构造函数,没有main函数
-
接口方法都是public
eg1.
animal接口:
public interface Animal{
public void eat();
public void move();
}
爬树接口
public interface ClimbTree{
public void climb();
}
抽象类陆地动物,实现animal这个接口
public abstract LandAnimal implements Animal{
public abstract void eat();//无法实现的方法,必须声明为abstract
public void move()
{
System.out.println("I can walk by feet.");
}
}
兔子类继承陆地动物并实现爬树接口:
public class Rabbit extends LandAnimal implements ClimbTree{//extends必须放在implements前面
public void climb(){
System.out.println("Rabbit: I can climb");
}
public void eat(){
System.out.println("Rabbit: I can eat");
}
}
猫科动物接口继承了多个接口
public interface CatFamily extends Animal,ClimbTree{
//eat();move();climb()//这所有继承过来的方法
}
类转型
类似于变量的类型相互转换,类的类型也可以,但只限于有继承关系的类。
性质:
-
子类可以转换成父类(由大变小,即向上转型),而父类不可以转换为子类(由小变大,即向下转型)
eg.Human obj1 = new Man();//new出来的是子类,可以转换成父类 Man obj2 = new Human();//new出来的是父类,不可以转换成子类,因为缺少子类独有的方法或属性
-
父类转为子类只有一种情况是可以的:
Human obj1 = new Man();//父类本身就是从子类转化而来的 Man obj2 = (Man)obj1;
多态
重写:由于子类方法的优先级高于父类,所以子类可以重新定义一个名字、参数和父类一样的方法,这种行为就是重写(覆写(overwrite)、覆盖(override),注意不是重载(overload))
eg1.
public class Man extends Human{
public void eat()//子类重写父类的eat方法
{
System.out.println("I can eat more");
}
public void plough(){}//子类独有的方法
//main函数
public static void main(String[] a)
{
Man obj1 = new Man();
obj1.eat(); //执行的是Man.eat()
Human obj2 = (Human)obj1;
obj2.eat(); //这里依然是执行的Man.eat()!!!!因为obj2本身是脱胎于obj1,所以由于重写,父类的eat是被子类的eat覆盖了的
Man obj3 = (Man)obj2;
obj3.eat(); //这里依然是执行的Man.eat()!!!!
}
}
多态:多种不同对象(继承于同一父类的对象)的动态行为。即子类转型为父类后,所调用的普通方法,依旧是子类的本身的方法。
多态的作用:
- 以统一的接口(父类)来操纵某一类(父类)中不同的对象(不同的子类)的动态行为(子类的某一种方法,该方法重写于父类)
- 对象之间的解耦
Animal接口:
cat类实现animal接口:public interface Animal{ public void eat(); public void move(); }
dog类实现animal接口:public class Cat implements Animal{ public void eat() { System.out.println("Cat: I can eat."); } public void move() { System.out.println("Cat: I can move"); } }
main函数(多态作用的展示)public class Dog implements Animal{ public void eat() { System.out.println("Dog: I can eat."); } public void move() { System.out.println("Dog: I can move"); } }
public class AnimalTest{ //main函数 public static void main(String[] args){ Animal[] as = new Animal[4];//Animal是一个接口,这里为什么能new????????? //这里都在做隐含的转型操作 as[0] = new Cat(); as[1] = new Dog(); as[2] = new Cat(); as[3] = new Dog(); for(int i=0;i<as.length;i++) { as[i].move();//这里就可以用统一的接口(方式)来遍历一个结构(数组)中每个元素的一个方法 } //下面都是解耦的例子 for(int i=0;i<as.length;i++) { haveLunch(as[i]);//这是main函数中调用类的方法的操作 } haveLunch(new Cat());//隐藏的转型操作 haveLunch( new Animal(){//这里因为animal是一个接口,所以要想让它new,必须在此时将他的方法体补充出来,形成一个匿名的类 public void eat{ System.out.println("I can eat from an anonymous class"); } public void move{ System.out.println("I can move from an anonymous class"); } }) } public static void haveLunch(Animal a)//这是被调用类的方法,参数使用一个接口,来规范不同类的行为方法 { a.eat(); } }
契约设计
契约:规定规范了对象应该包含的行为方法(就是接口(接口定义了方法的名称、参数和返回值,规范了派生行为))
契约设计:类不会直接调用另外一个类,而是采用接口的形式,外部可以“空投”这个接口下的任意子类对象
契约设计就是Java总是使用接口来使调用类和被调用类解耦。意思就是在main函数的一个调用操作,可以放入不同类的参数(这个不同的类,必须是继承于同一父类)