面向对象
面向对象和面向过程的区别
- 面向过程 :面向过程性能比面向对象高。 因为类调用时需要实例化,开销比较大,比较消耗资源,所以当性能是最重要的考量因素的时候,比如单片机、嵌入式开发、Linux/Unix 等一般采用面向过程开发。但是,面向过程没有面向对象易维护、易复用、易扩展。
- 面向对象 :面向对象易维护、易复用、易扩展。 因为面向对象有封装、继承、多态性的特性,所以可以设计出低耦合的系统,使系统更加灵活、更加易于维护。但是,面向对象性能比面向过程低。
构造器
构造方法类似于python中的__init_()
,主要作用是完成类对象的初始化工作。
如果一个类没有声明构造方法,也可以执行。因为即使没有声明,java会默认添加不带参数的构造方法。[在class文件内会自动生成]
如果自定义添加了类的构造方法,java就不会自动添加了。定义了有参构造器之后一定要默认加一个无参构造。
构造方法看起来像一个方法,但是与方法不同,构造方法没有返回值,甚至没有void。
构造方法的特点:
- 名字与类名相同。
- 没有返回值,但不能用 void 声明构造函数。
- 生成类的对象时自动执行,无需调用。
构造方法不能被 override(重写),但是可以 overload(重载),所以你可以看到一个类中有多个构造函数的情况。
类名 方法 字段
类声明的格式,关键字class后面跟类名(每个单词首字母大写,驼峰命名)。类的主体放入大括号中:
class ClassName{
[类主体]
}
public类的定义必须保存在与类名文件相同的文件中,这个限制不适用于非公共类。
字段是变量,可以是基本类型,也可以是引用类型。(首字母小写,驼峰命名)
方法,类似于python中的函数,定义了一个类可以执行的动作。方法包括声明部分和主体部分。声明部分由返回值、方法名和参数列表组成。主体包含操作执行的代码。
修饰符 返回值类型 方法名(参数类型 参数名){
...
方法体
...
return 返回值;
}
面向对象三大特性
- 封装
封装是指把一个对象的状态信息(也就是属性)隐藏在对象内部,不允许外部对象直接访问对象的内部信息。但是可以提供一些可以被外界访问的方法来操作属性。就好像我们看不到挂在墙上的空调的内部的零件信息(也就是属性),但是可以通过遥控器(方法)来控制空调。如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。就好像如果没有空调遥控器,那么我们就无法操控空凋制冷,空调本身就没有意义了(当然现在还有很多其他方法 ,这里只是为了举例子)。
public class Student {
private int id;//id属性私有化
private String name;//name属性私有化
//获取id的方法
public int getId() {
return id;
}
//设置id的方法
public void setId(int id) {
this.id = id;
}
//获取name的方法
public String getName() {
return name;
}
//设置name的方法
public void setName(String name) {
this.name = name;
}
}
- 继承
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承,可以快速地创建新的类,可以提高代码的重用,程序的可维护性,节省大量创建新类的时间 ,提高我们的开发效率。
关于继承如下 3 点请记住:
- 子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问,只是拥有。
- 子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。(以后介绍)。
- 多态
多态,顾名思义,表示一个对象具有多种的状态。
值传递还是引用传递
先说结论:java基本类型变量作为实参进行传递时,是值传递,方法内部局部变量的修改不会影响传入的基本类型变量值。
当传递引用变量是,局部变量会引用与传入的引用变量相同的对象。如果更改方法中引用的对象,由于形参和实参指的是同一个内存地址,所以局部变量的改变会影响到实际的对象。
方法重载
- 方法名称相同
- 方法的参数列表必须不同,返回值不限制。(因为首先执行方法,必须参数不同java才能知道执行哪个方法)
- 静态方法也可以重载
重载是发生在编译时的,因为编译器可以根据参属的类型来选择使用哪个方法。 ``` public class Apple { int sum; String color;
public Apple(){} public Apple(int sum){}
public int getApple(int num){
return 1;
} public String getApple(String color){
return "color";
} }
## 命令行参数
有时候你希望运行一个程序时候再传递给它消息。这要靠传递命令行参数给main()函数实现。<br />命令行参数是在执行程序时候紧跟在程序名字后面的信息。
public class CommandLine { public static void main(String args[]){ for(int i=0; i<args.length; i++){ System.out.println(“args[“ + i + “]: “ + args[i]); } } }
```
$ javac CommandLine.java
$ java CommandLine this is a command line 200 -100
args[0]: this
args[1]: is
args[2]: a
args[3]: command
args[4]: line
args[5]: 200
args[6]: -100
内存分析
当程序运行时,系统会为数据分配一些内存空间。这种数据空间在逻辑上氛围两个部分,堆(heap)和栈(stack)。基本类型值在栈中分配,java对象则在堆中。
堆栈、堆、方法区
JAVA
的JVM
的内存可分为3个区:堆(heap)、堆栈(stack)和方法区(method)
- 堆区:
提供所有类实例和数组对象存储区域
jvm
只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身
- 栈区:
每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中
每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
- 方法区:
又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。
方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。
运行时常量池都分配在 Java 虚拟机的方法区之中
接口和抽象类
- 抽象类
不能new这个抽象类,只能继承
抽象类中可以写普通方法,但抽象方法必须在抽象类中。
抽象类的方法必须由字类重写
- 接口
接口就是规范,定义的是一组规则。接口相当于就是对外的一种约定和标准。
接口不能被实例化,没有构造方法
implements可以继承多个接口
必须重写接口中的方法。
在java
语言中,接口是由interface
关键字来表述的,比如可以像下面这样定一个接口:
// interface 定义接口的关键字
// 抽象的思维
public interface UserService {
// 接口中的所有定义其实都是抽象的 public
public void run();
public abstract void go();
//返回值类型 方法名(参数)
void add();
void delelte();
void update();
void query();
}
public class UserServiceImpl implements UserService{
@Override
public void run() {
}
@Override
public void go() {
}
@Override
public void add() {
}
@Override
public void delelte() {
}
@Override
public void update() {
}
@Override
public void query() {
}
}
this 和super
- 从本质上讲,this 是一个指向本对象的指针, 然而 super 是一个 Java 关键字。
- Super() this() 分别可以调用父类和当前类的构造方法。但是在调用的构造方法中,他们都必须在第一行。
super.
this.
分别可以调用父类和当前类的属性字段。- this() 和 super() 都指的是对象,所以,均不可以在 static 环境中使用。包括:static 变量,static 方法,static 语句块。
public class Person {
public void prt(String s) {
System.out.println(s);
}
Person() {
prt("父类·无参数构造方法: "+"A Person.");
}//构造方法(1)
Person(String name) {
prt("父类·含一个参数的构造方法: "+"A person's name is " + name);
}//构造方法(2)
}
public class Chinese extends Person {
Chinese() {
super(); // 调用父类构造方法(1)
prt("子类·调用父类无参数构造方法: "+"A chinese coder.");
}
Chinese(String name) {
super(name);// 调用父类具有相同形参的构造方法(2)
prt("子类·调用父类含一个参数的构造方法: "+"his name is " + name);
}
Chinese(String name, int age) {
this(name);// 调用具有相同形参的构造方法(3)
prt("子类:调用子类具有相同形参的构造方法:his age is " + age);
}
public static void main(String[] args) {
Chinese cn = new Chinese();
cn = new Chinese("codersai");
cn = new Chinese("codersai", 18);
}
}
父类·无参数构造方法: A Person.
子类·调用父类无参数构造方法: A chinese coder.
父类·含一个参数的构造方法: A person's name is codersai
子类·调用父类含一个参数的构造方法: his name is codersai
父类·含一个参数的构造方法: A person's name is codersai
子类·调用父类含一个参数的构造方法: his name is codersai
子类:调用子类具有相同形参的构造方法:his age is 18
Process finished with exit code 0
instanceof
判断类之间的关系,是否存在父子关系。
static
static修饰符,用于修饰类的成员方法,类的成员变量,另外可以编写static代码块。
static修饰变量和方法,方便在没有创建对象的情况下进行调用。很显然,被static关键字修饰的方法和变量不需要依赖于对象来进行访问,只要类被加载了,就可以通过类名进行访问。
- static修饰成员方法
static修饰的方法一般被称作静态方法,无需创建对象,通过类名就可以访问。我们的main方法就是static方法。
- static修饰成员变量
static修饰的成员变量也称为静态变量,静态变量和非静态变量的区别是:静态变量当且仅当类初次加载时就会被初始化。而非静态变量是对象所拥有的,在创建对时才会被初始化。
- static修饰代码块
static还有一个比较关键的作用就是用来形成静态代码块以优化程序性能。
static块可以放置在类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来依次执行。只会在类初次被加载的时候执行一次。
static关键字的误区