目录
1、面向过程和面向对象
2、对象和类的概念
3、面向过程的内存分析
4、构造方法
5、垃圾回收机制
6、开发中容易造成内存泄露的操作
7、this关键字
8、static 关键字
9、包(package)
10、JAVA中的常用包
11、继承
12、方法的重写(override)
13、Object类
14、继承树追溯
15、封装
16、多态
17、final关键字
18、abstract关键字
19、接口
20、内部类
21、String类
1、面向过程和面向对象
面向过程:按步骤解决问题(开车)面向对象:根据组成部分设计事物(造车)面向对象具有三大特征:封装性、继承性和多态性面向过程和面向对象都是解决问题的思维方式,都是代码组织的方式解决简单问题一般使用面向过程的方式解决复杂问题时宏观上需要使用面向对象的方式,但微观处理上仍然是面向过程
2、对象和类的概念
类:class对象:Object,instance(实例)类是模版,可以根据类的定义来造出对象,一般称对象是类的实例类有三种常见成员:属性field、方法method、构造器constructor,都可以定义零个或多个instanceof是二元运算符,左操作数是对象,右操作数是类,当对象是该类或子类所创建时,返回true,否则返回false
3、面向过程的内存分析
栈
栈的存储特性是“先进后出,后进先出”栈描述的是方法执行的内存模型,每个方法被调用都会创建一个栈帧栈是由系统自动分配栈的一个连续的内存空间JVM为每个线程创建一个私有栈,用于存放该线程执行方法的信息,线程间不能共享
堆
堆本质是一个二叉树,是不连续的内存空间,分配灵活但速度慢堆用于存储创建好的对象和数组(数组也是对象)JVM只有一个堆,被所有线程共享
方法区(静态区)
方法区实际也是堆(但和上文不是一个东西),JVM只有一个方法区,被所有线程共享方法去用来存放程序中永远不变或唯一的内容,如类信息、静态变量、字符串常量等
4、构造方法
构造方法也叫构造器,是一个创建对象时会自动调用的特殊方法,目的是对象的初始化构造器的名称应与类的名称一致Java通过new关键字来调用构造器,从而返回该类的实例构造器虽然有返回值,但是不能定义返回值类型,也不能使用return如果我们没有定义构造器,则编译器会自动定义一个无参的构造函数构造方法也可以重载,用于创建参数不同的对象
class Point {
double x, y;
//构造器
public Point(double _x, double _y) {
x = _x;
y = _y;
}
//定义的方法
public double getDistance(Point p) {
return Math.sqrt((x - p.x) * (x - p.x) + (y - p.y) * (y - p.y));
}
}
public class TestConstructor {
public static void main(String[] args) {
Point p = new Point(3.0, 4.0);
Point origin = new Point(0.0, 0.0);//生成对象
System.out.println(p.getDistance(origin));
}
}
5、垃圾回收机制
对象空间的分配:使用new关键字创建对象即可对象空间的释放:将对象赋值null即可垃圾回收算法的目的:发现无用的对象并回收无用对象占用的内存空间
引用计数法
堆中每个对象都有一个引用计数。每被引用一次计数加1,当被引用变量值变为null时计数减1,直到计数为0,则表示变成无用对象。优点是算法简单,缺点是“循环引用的无用对象”(两个对象相互引用)无法别识别。
引用可达法(根搜索算法)
程序把所有的引用关系看作一张图,从一个节点GC ROOT开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点。当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点。
分代垃圾回收机制
JVM将对象分为三种状态:年轻代、年老代和持久代,堆内存分别划分为 Eden、Survivor 和 Tenured/Old 空间。所有新生成的对象绝大多数都是放在Eden区,对应的是Minor GC。当Eden满了(达到一定比例)不能创建新对象时,则触发垃圾回收(GC),将无用对象清理掉,然后剩余对象复制到某个Survivor中,同时清空Eden和另一个Survivor。在年轻代中经历了N(默认15)次垃圾回收后仍然存活的对象,就会被放到Tenured中,对应的是Major GC。当Tenured满了时就需要启动Full GC,全面清理年轻代区域和年老代区域。在对JVM调优的过程中,很大一部分工作就是对于Full GC的调节。持久代区域用于存放静态文件,如Java类、方法等,对垃圾回收没有显著影响。
6、开发中容易造成内存泄露的操作
创建大量无用对象:比如,在需要大量拼接字符串时使用了String而不是StringBuilder: String str = "";
for (int i = 0; i < 10000; i++) {
str += i; //相当于产生了10000个String对象
} 静态集合类的使用:像HashMap、Vector、List等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,所有的对象占用的内存都不能被释放。各种连接对象未关闭:IO流对象、数据库连接对象、网络连接对象等连接对象属于物理连接,和硬盘或者网络连接,不使用的时候一定要关闭。监听器的使用:释放对象时,没有删除相应的监听器。
7、this关键字
String str = "";
for (int i = 0; i < 10000; i++) {
str += i; //相当于产生了10000个String对象
} 静态集合类的使用:像HashMap、Vector、List等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,所有的对象占用的内存都不能被释放。各种连接对象未关闭:IO流对象、数据库连接对象、网络连接对象等连接对象属于物理连接,和硬盘或者网络连接,不使用的时候一定要关闭。监听器的使用:释放对象时,没有删除相应的监听器。使用this来指明当前对象,即指明该方法为当前类中的方法而不是其它类中的同名方法使用this关键字调用重载的构造方法,避免相同的初始化代码,必须位于构造方法的第一句:
TestThis(int a, int b) {
this(); // 调用无参的构造方法,并且必须位于第一行!
this.a = a;
this.b = b;
}
//重载
TestThis(int a, int b, int c) {
this(a, b); // 调用带参的构造方法,并且必须位于第一行!
this.c = c;
} this不能用于static方法中
8、static 关键字
在类中,用static声明的成员变量为静态成员变量,也称为类变量。 类变量的生命周期和类相同,在整个应用程序执行期间都有效。static修饰的成员变量和方法从属于类,普通变量和方法从属于对象。即static成员变量只有一份,被该类的所有对象共享。在static声明的方法中不可直接访问非static的成员。静态初始化块(static声明的语句块)可以用于类的初始化,但不能直接访问非static成员。
9、包(package)
包对于类,相当于文件夹对于文件的作用,用于解决类重名的问题通常是类的第一句非注释性语句域名倒着写即可,再加上模块名,便于内部管理类写项目时都要加包,不要使用默认包
10、JAVA中的常用包
java.lang
包含一些Java语言的核心类,如String、Math、Integer、System和Thread,提供常用功能
java.awt
包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)
java.net
包含执行与网络相关的操作的类
java.io
包含能提供多种输入/输出功能的类
java.util
包含一些实用工具类,如定义系统特性、使用与日期日历相关的函数
导入包
Java会默认导入java.lang包下所有的类,因此这些类我们可以直接使用如果我们要使用其他包的类,需要使用import导入JDK1.5新增了静态导入,用于导入指定类的静态属性,这样可以直接使用静态属性
11、继承
如果新定义一个Student类,发现已经有Person类包含了我们需要的属性和方法,那么Student类只需要继承Person类即可拥有Person类的属性和方法继承使用extends关键字,如class Student extends Person被继承的类称为父类,也称作超类、基类、派生类等Java中类没有多继承,以免引起混乱,而接口有多继承子类继承父类,可以得到父类的全部属性和方法 (除了父类的构造方法),但不一定可以直接访问(例如父类私有的属性和方法)如果定义一个类时没有调用extends,则它的父类是:java.lang.Object
12、方法的重写(override)
//方法的声明
权限修饰符 返回值类型 方法名(形参列表) throws 异常的类型{
方法体
}
子类通过重写父类的方法,可以用自身的行为替换父类的行为方法的重写是实现多态的必要条件子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符被重写的方法的返回值类型是A类型,则重写的方法的返回值类型是A类或A类的子集重写前后方法名和形参列表必须相同子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型子类不能重写父类中声明为privite权限的方法super是直接父类对象的引用,可以通过super来访问父类中被子类覆盖的方法或属性
13、Object类
Object类是所有类的根基类Object类中定义有public String toString()方法,其返回值是 String 类型,在打印输出或者用字符串连接对象时,会自动调用该对象的toString()方法,需要时可以重写:
class Person {
String name;
int age;
//重写toString
public String toString() {
return name+",年龄:"+age;
}
}
public class Test {
public static void main(String[] args) {
Person p=new Person();
p.age=20;
p.name="李东";
System.out.println("info:"+p);//自动调用toString
}
} Object类中定义有public boolean equals(Object obj)方法,默认比较两个对象的hashcode,是同一个对象的引用时返回true,否则返回false在实际开发中,大部分是两个不同引用对象之间的比较,此时再用object的equals方法就不行了,因此就要根据自己的需求重写equals方法JDK提供的一些类,如String、Date、包装类等,重写了equals方法,调用这些类的equals方法:x.equals (y) ,当x和y所引用的对象是同一类对象且属性内容相等时(并不一定是相同对象)返回 true ,否则返回 false
14、继承树追溯
属性/方法查找顺序
- 查找当前类中有没有该属性/方法依次上溯每个父类,查看每个父类中是否有该属性/方法,直到Object只要找到该属性/方法,查找过程终止如果没找到,则出现编译错误
构造方法调用顺序
先向上追溯到Object,然后再依次向下执行类的初始化块和构造方法,直到当前子类为止静态初始化块调用顺序,与构造方法调用顺序一样
15、封装
封装就是把对象的属性和操作结合为一个独立的整体,并尽可能隐藏对象的内部实现细节提高代码的安全性提高代码的复用性“高内聚”:封装细节,便于修改内部代码,提高可维护性“低耦合”:简化外部调用,便于调用者使用,便于扩展和协作Java通过使用private、default(没有修饰符)、protected、public这四个“访问控制符”来控制哪些细节需要封装,哪些细节需要暴露的,具体访问权限如下图:
16、多态
多态指的是同一个方法调用,由于对象不同可能会有不同的行为多态是方法的多态,不是属性的多态(多态与属性无关)多态的存在要有3个必要条件:继承,方法重写,父类引用指向子类对象父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了
class Animal {
public void shout() {
System.out.println("叫了一声!");
}
}
class Dog extends Animal {
public void shout() {
System.out.println("旺旺旺!");
}
public void seeDoor() {
System.out.println("看门中....");
}
}
class Cat extends Animal {
public void shout() {
System.out.println("喵喵喵喵!");
}
}
public class Test {
public static void main(String[] args) {
//向上可以自动转型
Animal a1 = new Cat();
animalCry(a1);
Animal a2 = new Dog();
animalCry(a2);
//向下只能进行强制类型转换
Dog dog = (Dog)a2;
dog.seeDoor();
}
// 有了多态,只需要让增加的这个类继承Animal类就可以了。
static void animalCry(Animal a) {
a.shout();
}
} 在向下转型过程中,为了确保转型正确,可以先使用instanceof运算符进行判断
17、final关键字
修饰变量: 该变量不可改变,一旦赋了初值就不能被重新赋值修饰方法:该方法不可被子类重写,但是可以被重载修饰类: 该类不能被继承
18、abstract关键字
抽象方法:使用abstract修饰的方法,没有方法体,只有声明抽象类:包含抽象方法的类就是抽象类抽象类不能实例化,只能用来被继承,抽象方法必须被子类实现:
//抽象类
abstract class Animal {
abstract public void shout(); //抽象方法
}
class Dog extends Animal {
//子类必须实现父类的抽象方法,否则编译错误
public void shout() {
System.out.println("汪汪汪!");
}
public void seeDoor(){
System.out.println("看门中....");
}
}
public class Test {
public static void main(String[] args) {
Dog a = new Dog();
a.shout();
a.seeDoor();
}
} 老板给员工画的大饼由员工自己实现!
19、接口
接口是彻底的“抽象类”,抽象类还提供某些具体实现,而接口的所有方法都是抽象方法。 面向对象的精髓,是对对象的抽象,最能体现这一点的就是接口。接口就是规范,定义的是一组规则,类似于“如果你是……就一定能……”。举例:如果它是交通工具,就一定能跑;如果你是鸟,就一定能飞……
[访问修饰符] interface 接口名 [extends 父接口1,父接口2…] {
常量定义;
方法定义;
}
访问修饰符:只能是public或默认接口名:和类名采用相同命名机制extends:接口可以多继承常量:接口中的属性只能是常量,写不写都是以public static final 修饰方法:接口中的方法只能是public abstract修饰,写不写都是
public class Test {
public static void main(String[] args) {
Volant volant = new Angel();
volant.fly();
System.out.println(Volant.FLY_HIGHT);
Honest honest = new GoodMan();
honest.helpOther();
}
}
//飞行接口
interface Volant {
int FLY_HIGHT = 100;
void fly();
}
//善良接口
interface Honest {
void helpOther();
}
//天使类实现飞行接口和善良接口
class Angel implements Volant, Honest{
public void fly() {
System.out.println("我是天使,飞起来啦!");
}
public void helpOther() {
System.out.println("扶老奶奶过马路!");
}
}
//鸟人类实现飞行接口
class BirdMan implements Volant {
public void fly() {
System.out.println("我是鸟人,正在飞!");
}
}
//好人类实现善良接口
class GoodMan implements Honest {
public void helpOther() {
System.out.println("扶老奶奶过马路!");
}
}
子类通过implements来实现接口中的规范接口不能创建实例,但是可用于声明引用变量类型一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是public的JDK1.7前,接口中只能包含静态常量、抽象方法,不能有普通属性、构造方法、普通方法JDK1.8后,接口中可以包含普通的静态方法
20、内部类
如果一个类放在另一个类的内部定义,该类被称为内部类内部类可以使用public、default、protected 、private以及static修饰,而外部顶级类只能使用public和default修饰内部类是相对独立的一种存在,其成员变量/方法名可以和外部类的相同内部类主要分为成员内部类(非静态内部类、静态内部类)、匿名内部类、局部内部类
成员内部类(可以使用private、default、protected、public修饰)
a)非静态内部类
非静态内部类必须寄存在一个外部类对象里非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员非静态内部类不能有静态方法、静态属性和静态初始化块外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例
class Outer {
private int age = 10;
class Inner {
int age = 20;
public void show() {
int age = 30;
System.out.println("内部类方法里的局部变量age:" + age);// 30
System.out.println("内部类的成员变量age:" + this.age);// 20
System.out.println("外部类的成员变量age:" + Outer.this.age);// 10
}
}
}
访问内部类里方法的局部变量:变量名访问内部类属性:this.变量名访问外部类属性:外部类名.this.变量名
public class TestInnerClass {
public static void main(String[] args) {
//外部类以外的地方使用非静态内部类
Outer.Inner inner = new Outer().new Inner();
inner.show();
Outer outer = new Outer();
Outer.Inner inn = outer.new Inner();
inn.show();
}
}
外部类中定义内部类:直接使用new Inner()外部类以外的地方使用非静态内部类:如上述代码
b) 静态内部类
当一个静态内部类对象存在,并不一定存在对应的外部类对象, 因此静态内部类的实例方法不能直接访问外部类的实例方法静态内部类看做外部类的一个静态成员, 因此外部类的方法中可以通过:“静态内部类.名字”的方式访问静态内部类的静态成员,通过 new 静态内部类()访问静态内部类的实例:
class Outer{
//相当于外部类的一个静态成员
static class Inner{
}
}
public class TestStaticInnerClass {
public static void main(String[] args) {
//通过 new 外部类名.内部类名() 来创建内部类对象
Outer.Inner inner =new Outer.Inner();
}
}
匿名内部类
new 父类构造器(实参类表) 实现接口 () {
//匿名内部类类体
}
适合那种只需要使用一次的类,比如键盘监听操作等匿名内部类没有访问修饰符和构造方法
this.addWindowListener(new WindowAdapter(){
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
);
this.addKeyListener(new KeyAdapter(){
@Override
public void keyPressed(KeyEvent e) {
myTank.keyPressed(e);
}
@Override
public void keyReleased(KeyEvent e) {
myTank.keyReleased(e);
}
}
);
局部内部类
局部内部类定义在方法,作用域只限于本方法局部内部类的的使用主要是想创建一个类来辅助解决复杂问题,但又不希望这个类公共可用局部内部类在实际开发中应用很少
21、String类
String位于java.lang包中,Java程序已默认导入Java没有内置的字符串类型,而是使用类String,每个用双引号括起来的字符串都是String类的一个实例,且允许使用符号"+"把两个字符串连接起来:
String e = "" ; // 空字符串 String s1 = "Hello"; String s2 = "World! "; String s = s1 + s2; //HelloWorld!String类常用的方法: 检测字符串内容是否相等:如果字符串s和t内容相等,则s.equals(t)返回true,否则返回false检测两个字符串除了大小写区别外是否相等:使用equalsIgnoreCase方法判断字符串是否相等不要使用"=="



