1.面向对象
现实世界是由对象和对象之间相互作用共同组成的;
每个对象都有自己的特有属性,也有自己专有的方法。对象要调用这些方法,可以向它请求并传入参数,等方法执行结束后,返回结果;
对象=属性+方法
对象的规范=属性定义+方法定义
Java中的对象和类的概念
- 对象是一个变量,一个具体的事物
- 类就是类型,从许多对象中抽取共性
- 类规定了对象应该有的属性内容和方法
- 对象是类的具体实现
基本类型是一种变量
结构体是多种变量的集合
类是多种变量和方法的集合
2.Java类
Java项目是由一个个类组成的
类是Java中的基础逻辑单元:
java所有的内容都要放在类的范围中
类的构成:
- 成员变量/属性
- 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
- 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
- 类变量:类变量也声明在类中,方法体之外,但必须声明为static类型。
- 成员方法/函数
public class MemberShow
{
int a=0; //成员变量 member variables
int b=5;
//不允许在这里写 System.out.println("hello"); 既不是变量也不是函数,非法
public void f1() //成员函数 member functions
{
System.out.println("Hello");
}
}
//不允许在这里写 System.out.println("hello")
Main函数
一个class最多只能有一个main函数(固定写法public static void main()——PSVM类型)类可以没有main函数,没有main函数的类不能主动执行,但可以被动执行,即被别人调用执行
程序的入口都是main函数,但与C/C++不同的是,代码都要放在class内
main函数是一个Java程序的总入口
mian函数无法被其他方法/类调用
一个Java程序可以调用多个其他Java class
String[] args是main函数的形参,即在main函数中可以使用args的值(在main函数启动时输入)
public class ArgumentTest
{
public static void main(String[] args)
{
for(int i=0;i<args.length;i++)
{
//依次将形参输出
System.out.println(args[i]);
}
}
}
注意:
Java文件必须以.java为扩展名
一个Java文件可以有多个类,但只能有一个public class
public class的名字必须和文件名字一样(大小写也一致)
类可以继承,子类可以继承父类所有内容(不能直接访问private成员)
public class Father {
private int money = 100; //私有
long mobile = 13999999999L;
public void hello() {
System.out.println("hello");
}
}
public class Son extends Father {
public void hi() {
//子类可以扩展自己的成员方法
System.out.println("hi~~~~~");
}
public static void main(String[] a) {
Son s = new Son();
System.out.println(s.mobile); //Son没有定义mobile, 而是通过父类继承的
//System.out.println(s.money); //error 父类的money是私有的,子类无法直接访问
s.hello(); //Son没有定义f1, 而是通过父类继承的
s.hi(); //Son可以自定义自己的成员方法
}
}
new方法产生对象,对象是类的实现,是实例。
public class ReferenceTest {
public static void main(String[] args) {
int num1 = 5;
int num2 = num1;
System.out.println("num1: " + num1 + ", num2: " + num2);
num2 = 10;
System.out.println("num1: " + num1 + ", num2: " + num2);
MyNumber obj1 = new MyNumber(); //num=5
MyNumber obj2 = new MyNumber();
System.out.println(obj1.num);
System.out.println(obj2.num);
System.out.println("======接下来输出新值=====");
obj2 = obj1;
obj2.num = 10; //obj1和obj2指向同一块内存
System.out.println(obj1.num);
System.out.println(obj2.num);
}
}
以上实例两个对象,类型都是A,但是是两个不同的对象,在内存中有不同的存放地址。
对象赋值是赋值,而基本类型是直接值拷贝
//对象复制是Refence赋值,而基本类型是直接值拷贝
//因为基本类型变量值小,可直接拷贝;对象包含多个值,不容易复制,复制采用共享同一块内存区域
public class ArgumentPassingTest {
public static void main(String[] args) {
int a = 1, b = 2;
swap(a,b); //交换
System.out.println("a is " + a + ", b is " + b); //a=1, b=2
MyNumber obj1 = new MyNumber();
MyNumber obj2 = new MyNumber();
obj2.num = 10;
swap(obj1, obj2);
System.out.println("obj1 is " + obj1.num + ", obj2 is " + obj2.num); // obj1 10, obj2 5
}
public static void swap(int m, int n) //调用时m=1,n=2
{ //m,n交换 与a,b无关
int s = m;
m = n;
n = s;
}
public static void swap(MyNumber obj3, MyNumber obj4) //obj1和obj3指向同一块内存
{
int s = obj3.num;
obj3.num = obj4.num;
obj4.num = s;
}
}
3.继承
面向对象编程的特点是变量类型的继承,避免了面向过程编程的类型重复定义问题
子类继承父类所有的属性和方法,但不能直接访问private成员
根据信息隐藏原则:子类会继承父类所有的方法,可以直接使用
子类也会继承父类的父类的所有属性和方法,但不能直接访问private成员
单根继承原则:每个类都只能继承一个类
如果不写extends,Java类默认继承java.long.Object类
每个Java类都必须有构造函数
如果没有显式定义构造函数,Java编译器自动为该类产生一个空的无形参构造函数,如果已经有了显式的有参构造函数,编译器就不会自动产生。
每个子类构造函数的第一句话,都默认调用父类的无参构造函数super(),除非子类的构造函数第一句话是super,而且super语句必须放在第一条,不会出现连续的两条super语句
public class A {
public A()
{
System.out.println("111111");
}
public A(int a)
{
System.out.println("222222");
}
}
public class B extends A{
public B()
{
//super(); 编译器自动增加super()
System.out.println("333333");
}
public B(int a)
{
super(a); //编译器不会自动增加super();
System.out.println("444444");
}
public static void main(String[] a)
{
B obj1 = new B();
System.out.println("==============");
B obj2 = new B(10);
}
}
this关键字
class Animal {
void eat() {
System.out.println("animal : eat");
}
}
class Dog extends Animal {
void eat() {
System.out.println("dog : eat");
}
void eatTest() {
this.eat(); // this 调用自己的方法
super.eat(); // super 调用父类方法
}
}
public class Test {
public static void main(String[] args) {
Animal a = new Animal();
a.eat();
Dog d = new Dog();
d.eatTest();
}
}
static关键字
静态变量,类公有成员
static变量只依赖于类存在(通过类即可访问),不依赖与对象实例存在
所有的对象实例的值都共享存储在一个共同的空间
静态方法无需通过对象来引用,而通过类名可以直接引用;
在静态方法中,只能使用静态变量,不能使用非静态变量;
静态方法禁止引用非静态方法;
static块只在第一次被加载时调用(即在过程中只运行一次);
执行顺序:static块>匿名块>构造函数
public class Potato {
static int price = 5;
String content = "";
public Potato(int price, String content)
{
this.price = price;
this.content = content;
}
public static void main(String[] a)
{
System.out.println(Potato.price); //Potato.content wrong
System.out.println("----------------------------------");
Potato obj1 = new Potato(10,"青椒土豆丝");
System.out.println(Potato.price); //10
System.out.println(obj1.price); //10
System.out.println("----------------------------------");
Potato obj2 = new Potato(20,"酸辣土豆丝");
System.out.println(Potato.price); //20
System.out.println(obj2.price); //20
}
}
final关键字:
final的类,不能被继承(父类中如果有final方法,子类中不能改写此方法)
final的变量,不能再次赋值
如果是基本类型的变量,不能修改其值
如果是对象实例,不能修改其指针,但可以修改对象内部的值
class FinalObject
{
int a = 10;
}
public class FinalObjectTest {
public static void main(String[] args) {
final FinalObject obj1 = new FinalObject();
System.out.println(obj1.a);
obj1.a = 20;
System.out.println(obj1.a);
//obj1 = new FinalObject(); Wrong
//final对象不能变更指针
}
}
java继承是单继承,也可以多重继承
4.抽象类和接口
一个完整的类所有的方法都要实现
类可以没有方法,但是有方法要有实现才是一个完整的类
一个完整的类才可以被实例化,被new
如果一个类暂时有方法没有实现,需要被定义为抽象类
抽象类用关键字abstract声明
抽象类的组成:
成员变量,具体方法,抽象方法(一个或多个)
注意:一个类继承于抽象类,就不能继承于其他的(抽象)类
子类可以继承与抽象类,但是一定要实现父类们所有abstract的方法,如果不能完全实现,那么子类也必须被定义为抽象类
只有实现父类们的所有抽象方法,才变成完整类
接口:
如果所有类的所有方法都没有实现,那么这个类就算是接口interface
接口是“特殊”的类
类只可以继承(extends)一个类,但是可以实现(implements)多个接口,继承和实现可以同时。
接口可以继承(多个)接口,没有实现的方法将会叠加
类实现接口,就必须实现所有未实现的方法,如果没有全部实现,就只能成为一个抽象类
抽象类和接口两者都不能被实例化,不能new操作
区别是抽象类可以有部分实现,接口所有方法不能有实现;一个类只能继承一个抽象类,实现多个接口;
接口可以继承多个接口。
抽象类有构造函数,接口没有构造函数。
//Animal接口
public interface Animal {
public void eat();
public void move();
}
//ClimbTree接口
public interface ClimbTree {
public void climb();
}
//LandAnimal抽象类
public abstract class LandAnimal implements Animal {
public abstract void eat() ;
public void move() {
System.out.println("I can walk by feet");
}
}
//Rabbit类
public class Rabbit extends LandAnimal implements ClimbTree {
public void climb() {
System.out.println("Rabbit: I can climb");
}
public void eat() {
System.out.println("Rabbit: I can eat");
}
}
5.转型和多态
转型
变量支持相互转换,比如int a=(int)3.5;
类型可以相互转换,但是只限制于有继承关系的类。
子类可以转换成父类,而父类不可以转为子类。
子类继承父类所有的财产,子类可以变成父类(从大变小,即向上转型);
从父类直接变成子类(从小变大,即向下转型)则不允许。
父类可以转换成子类的一种例外情况,就是这个父类本身就是从子类转换来的
public class Human {
int height;
int weight;
public void eat() {
System.out.println("I can eat!");
}
}
public class Man extends Human {
public void eat() {
System.out.println("I can eat more");//子类重写父类eat方法
}
public void plough() { } //父类没有的方法
public static void main(String[] a) {
Man obj1 = new Man();
obj1.eat(); // call Man.eat()
Human obj2 = (Human) obj1; //转型成父类
obj2.eat(); // call Man.eat()
Man obj3 = (Man) obj2; //
obj3.eat(); // call Man.eat()
}
}
多态
多态的定义
同一操作作用于不同类的实例,将产生不同的执行结果,即不同类的对象收到相同的消息时,得到不同的结果
多态性的两种类型
- 静态多态性
是指定义在一个类或一个函数中的同名函数,它们根据参数表(类型以及个数)区别语义和执行的功能
程序在编译时,系统就能决定调用哪个函数,如重载。
- 动态多态性
指定义在一个类层次下的不同类中的覆盖函数,它们具有相同的函数原型,需要根据指针指向的对象的所在类来区别语义
在运行中才能动态确定操作指针所指的对象,主要通过虚函数和重写来实现。
子类继承父类的所有方法,但子类可以重新定义一个名字,参数和父类一样的方法,但这种行为就是重写(overwrite),不同于重载(overload)
子类的方法的优先级高于父类的
多态的作用:
- 提高了程序的灵活性,提高了编程效率,程序员可以使用统一形式实现不同功能的调用,如以统一的接口来操纵某一类中不同的对象的动态行为。
- 对象之间的解耦
//Animal接口
public interface Animal {
public void eat();
public void move();
}
//Cat类
public class Cat implements Animal //继承animal
{
public void eat() {
System.out.println("Cat: I can eat");
}
public void move(){
System.out.println("Cat: I can move");
}
}
//Dog类
public class Dog implements Animal //继承animal
{
public void eat() {
System.out.println("Dog: I can eat");
}
public void move() {
System.out.println("Dog: I can move");
}
}
public class AnimalTest {
public static void haveLunch(Animal a) {
a.eat(); //调用eat方法,27行
}
public static void main(String[] args) {
Animal[] as = new Animal[4]; //new animal数组
as[0] = new Cat(); //隐含cat转型成animal父类
as[1] = new Dog();
as[2] = new Cat();
as[3] = new Dog();
for(int i=0;i<as.length;i++) { //多态:以统一的接口来操纵某一类中不同的对象的动态行为
as[i].move(); //调用每个元素的自身的move方法(子类的)
}
for(int i=0;i<as.length;i++) { //多态另一作用:解耦
haveLunch(as[i]);
}
haveLunch(new Cat()); //Animal a = new Cat(); haveLunch(a);
haveLunch(new Dog());
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");
}
});
}
}
//子类转型为父类后,调用普通方法,依旧是子类的方法