全部内容对外不可见(信息隐藏,用类进行封装)
功能继承下来继续发展,即子类继承父类非私有的方法和属性
重写@override | 重载@overload |
---|---|
子类父类中 | 一个类中 |
参数列表必须相同 | 参数列表必须不同 |
返回值类型必须一致 | 与返回值类型无关 |
子类访问权限必须不能小于父类的访问权限 | 与访问权限无关 |
可以减少或删除(异常范围更小,但不能抛出异常) | 与异常处理无关 |
对象的多种表现形式(多种体现形态)
在类中有子类、父类之分,子类为父类的一种形态
方法的多态性即相同的方法有多种形态
class 类名称{
成员属性;
成员方法;
}
属性定义: 数据类型 属性名;
属性定义并赋值:数据类型 属性名 = 初始化值;
权限修饰符 返回值类型 方法名(形式参数列表){
//方法体
return 返回值;//return 用来结束方法
}
一个类要想真正的进行操作,则必须依靠对象。
对象的定义:
类名称 对象名称 = new 类名称() ;
访问类中的属性: 对象.属性 ;
调用类中的方法: 对象.方法(实际参数列表);
例如:
int a =10;
Person p = new Person();
10存储在栈内存中 , 第二句代码创建的对象的引用( p )存在栈内存中
保存本地(native)方法的地址
构造方法(也叫构造函数):创建对象时自动调用,用于对象初始化
↓
类名 对象引用名 = new 构造方法();
Employee emp =new Employee();
当类中有非常量成员变量时,建议提供两个版本的构造方法,一个是无参构造方法,一个是全属性做参数的构造方法。
当类中所有成员变量都是常量或者没有成员变量时,建议不提供任何版本的构造。
方法的重载:在同一个类中用同一个名字表示不同的方法
重写override | 重载overload | |
---|---|---|
发生位置 | 子类父类中 | 同一个类中 |
参数列表限制 | 必须相同 | 必须不同 |
返回值类型 | 必须一致 | 与返回值无关 |
访问权限 | 子类访问权限≥父类 | 与访问权限无关 |
异常处理 | 可以减少or删除(使异常范围更小,但不能抛出新异常) | 与异常无关 |
例:
Math m = new Math();
int num = m.sum(1,2);
new Math();
int num = new Math().sum(1,2);
全部内容对外不可见(信息隐藏,用类进行封装)
对内:结构完整,可自我管理,自我平衡,高度集中
对外:功能明确,接口单一,各种环境独立工作
保护、防止代码及数据被无意中破坏
保护成员属性,不让类意外的程序直接访问和修改
仅对外公开访问方法,隐藏对象属性和实现细节(建议对所有的属性进行封装,并为其提供setter及getter方法进行设置和取得操作)
class Person{
String name ; // 表示姓名
int age ; // 表示年龄
void tell(){
System.out.println("姓名:" + name + ";年龄:" + age) ;
}
};
public class Demo{
public static void main(String args[]){
Person p = new Person() ;
p.name = "张三" ;
p.age = -30 ;
p.tell() ;
}
};
class Person{
private String name ; // 表示姓名
private int age ; // 表示年龄
void tell(){
System.out.println("姓名:" + getName() + ";年龄:" + getAge()) ;
}
public void setName(String str){
name = str ;
}
public void setAge(int a){
if(a > 0 && a < 150)
age = a ;
}
public String getName(){
return name ;
}
public int getAge(){
return age ;
}
};
public class Demo{
public static void main(String args[]){
Person p = new Person() ;
p.setName("张三") ;
p.setAge(-30) ;
p.tell() ;
}
例:
Person(){
this("张三",-30);//必须写在第一行
system.out.println("创建对象!");
}
编写在顺序执行的流程中出现的代码块
在类中的成员代码块
- 随着对象的每次创建,执行一次,且在构造方法之前
- 无论用户调用哪个构造方法创建对象,构造代码块都执行
【每次对象创建时执行, 执行在构造方法之前。】
例:
Class Person{
//构造代码块
{
System.out.prntln("创建对象!");
}
//构造方法
person(){};
Person(String name,int age){
this.name = name;
thia.age = age;
}
}
构造代码块前加上Static(在类中使用static修饰的成员代码块)
随着类加载,静态代码快执行
由于类只加载一次,因此静态代码块只执行一次
后续多线程技术中学习(待补充)
(即以下三个作用)
规范由来:
由于Java面向对象的特性,每名Java开发人员都可以编写属于自己的Java Package,为了保障每个JavaPackage命名的唯一性,在最新的Java编程规范中,要求开发人员在自己定义的包名前加上唯一的前缀。由于互联网上的域名称是不会重复的,所以多数开发人员采用自己公司在互联网上的域名称作为自己程序包的唯一前缀。例如:com.java.xxx
修饰符 | 类 | 包 | 子类 | 其他包 |
---|---|---|---|---|
public | √ | √ | √ | √ |
protected | √ | √ | √ | |
default(默认) | √ | √ | ||
private(封装) | √ |
局部变量和成员属性的区别:
局部变量 | 成员属性 | |
---|---|---|
定义的位置 | 方法 | 类 |
内存中的位置 | 存储在栈内存的方法中 | 存储在堆内存的对象中 |
声明周期 | 随着方法的运行而出现,随着方法的出栈而消失 | 随着对象的出现而出现,随着对象的消失而消失 |
初始化不同 | 没有默认初始化值,必须初始化后才可以使用 | 因为在堆内存中,所以有默认的初始化值 |
public:权限最大
static:表示它属于类的,随的类的加载而存在(如果是非static表示属于对象,只有建立对象时才有它)
final:不能被修改
public static void main(String args[])
- public:公共的内容,可以被所有操作所调用
- static:方法是静态的,可以由类名称直接调用。java StaticDemo09
- void:没有任何的返回值操作
- main:系统规定好的方法名称。如果main写错了或没有,会报错:NoSuchMethodError: main
- String[] args:字符串数组,接收参数的
随着类的加载在内存中对象为null,当调用 getInstance 方法时才创建对象(延迟加载)
优点:第一次调用才初始化,避免内存浪费。
缺点:必须加锁 synchronized 才能保证单例,但加锁会影响效率。
class Single1{
private Single1(){};
private static Single1 s1 = null;
public static Single1 getInstance(){//判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
if(s1 == null){
s1 = new Single1();
}
return s1;
}
}
随着类的加载直接创建对象(推荐开发中使用)
优点:没有加锁,执行效率会提高。
缺点:类加载时就初始化,浪费内存。
class Single2{
//让构造函数为 private,这样该类就不会被实例化
private Single2(){}
//创建 Single2的一个对象
private static Single2 s2 = new Single2();
//获取唯一可用的对象
public static Single2 getInstance(){
return s2;
}
void print(){
System.out.println("Hello World!");
}
}
public class SingleTest {
public static void main(String[] args) {
//不合法的构造函数,编译时会产生错误:构造函数 Single2() 是不可见的
//即Single2 object = new Single2();
//获取唯一可用的对象
Single2 s = Single2.getInstance();
//显示消息
s.printn();
}
}
格式:
abstract class 类名{ // 抽象类
}
格式:
abstract class 类名{ // 抽象类
public abstract void 方法名() ; // 抽象方法,只声明而未实现
}
=
interface 接口名称{
全局常量 ;
抽象方法 ;
}
class 子类 implements 父接口1,父接口2…{
}
class 子类 extends 父类 implements 父接口1,父接口2…{
}
接口因为都是抽象部分, 不存在具体的实现, 所以允许多继承
例如:
interface C extends A,B{
}
是接口定义(规范,约束)与实现(名实分离的原则)的分离。
接口都是由全局常量和抽象方法组成 , 所以接口中的成员定义可以简写:
1、全局常量编写时, 可以省略public static final 关键字,例如:(public static final )String INFO = “内容” ;
2、抽象方法编写时, 可以省略 public abstract 关键字, 例如:(public abstract) void print() ;
接口 | 抽象类 |
---|---|
被类实现 | 被子类继承 |
只能声明抽象方法 | 可以声明抽象方法,也可以声明非抽象方法 |
定义的变量只能是公共的静态常量 | 变量为普通变量 |
使用实现来使用,可以多实现 | 使用继承来使用,无法多继承 |
不能有构造方法 | 可以有构造方法 |
不允许包含static方法(接口中的都要被子类重写,静态方法不允许被重写) | 可以包含static方法 |
在类中有子类、父类之分,子类为父类的一种形态
方法的多态性即相同的方法有多种形态
类似于基本数据类型的转换:
public static void say(Person p){
if (p instanceof Student){//判断对象p是否为学生类
Student s = (Student)p;
s.say();
}else {
System.out.println("必须传入学生形态!");
}
}
使用Object可以接收任意的引用数据类型
例:
public static void main(String[] args){
String text = "123";
say(text);
int a = 10;
say(a);
say("123");
}
public static void say(Object o){//多态的体现
System.out.println(o);
}
equals方法重写时的五个特性:
自反性 :对于任何非空的参考值x , x.equals(x)应该返回true 。
对称性 :对于任何非空引用值x和y , x.equals(y)应该返回true当且仅当y.equals(x)返回true 。
传递性 :对于任何非空引用值x ,y和z ,如果x.equals(y)回报true并且y.equals(z)返回true,x.equals(z)应该返回true 。
一致性 :对于任何非空引用值x和y ,多次调用x.equals(y)始终返回true或始终返回false ,前提是未修改对象上的equals比较中使用的信息。
非空性 :对于任何非空的参考值x , x.equals(null)应该返回false 。
class Outer {
private double x = 0;
public Outer(double x) {
this.x = x;
}
//内部类
class Inner {
public void say() {
System.out.println("x=" + x);
}
}
}
在外部使用成员内部类:
Outter o = new Outter();
Outter.Inner i = o.new Inner();
class Person{
public Person() {}
}
class Man{
public Man(){}
public People getPerson(){
//局部内部类
class Student extends People{
int age =0;
}
return new Student();
}
}
构造方法:
new 父类构造器(参数列表)| 实现接口()
{
//匿名内部类的类体部分
}
格式:
class Outter {
public Outter() {}
static class Inner {
public Inner() {}
}
}
在外部使用静态内部类:
//区别于成员内部类
//由于静态,因此可以直接用 外部类.内部类 创建对象
Outter.Inner i = new Outter.Inner();
基本数据类型 | 占用内存(字节) | 包装类 |
---|---|---|
字节型byte | 1 | Byte |
短整数型short | 2 | Short |
整数型int | 4 | Integer |
长整数型long | 8 | Long |
浮点型float | 4 | Float |
双精度型double | 8 | Double |
字符型char | 2 | Character |
布尔型boolean | 1 | Boolean |
拆箱:(父类Number中定义了如下方法)
方法 | 描述 |
---|---|
public byte byteValue() | Byte→byte |
public abstract double doubleValue() | Double→double |
public abstract float floatValue() | Float→float |
public abstract int intValue() | Integer→int |
public abstract long longValue() | Long→long |
public short shortValue() | Short→short |
装箱:
int temp = 10 ; // 基本数据类型
Integer x = new Integer(temp) ; //装箱
int a = x.intValue();//拆箱
Float f = 10.3f ; // 自动装箱
float x = f ; // 自动拆箱
System.out.println(f * f) ; // 直接利用包装类完成
System.out.println(x * x) ; // 直接利用包装类完成
String→int:public static int parseInt(String s)
String→Float:public static float parseFloat(String s)
String→boolean:public static boolean parseBoolean(String s)
返回值类型 方法名称(数据类型…参数名称){
//参数在方法内部 , 以数组的形式来接收
}
异常处理、finally关键字以及finally常见面试题
在程序中导致程序中断运行的一种指令流。
异常指的是Exception , Exception类, 在Java中存在一个父类Throwable(可能的抛出)
Throwable存在两个子类:
1.Error:表示的是错误,是JVM发出的错误操作,只能尽量避免,无法用代码处理。
2.Exception:一般表示所有程序中的错误,所以一般在程序中将进行try…catch的处理。
try{
// 有可能发生异常的代码段
}catch(异常类型1 对象名1){
// 异常的处理操作
}catch(异常类型2 对象名2){
// 异常的处理操作
} …
finally{
// 异常的统一出口
}
try{
// 有可能发生异常的代码段
}catch(异常类型1 对象名1){
// 异常的处理操作
}catch(异常类型2 对象名2){
// 异常的处理操作
} …
finally{
// 异常的统一出口
}
try{
// 有可能发生异常的代码段
}catch(异常类型1 | 异常类型2 对象名){
// 异常的处理操作
}
finally{
// 异常的统一出口
}
try{
// 有可能发生异常的代码段
}catch(RuntimeException 对象名){
// 异常的处理操作
}
finally{
// 异常的统一出口
}
返回值 方法名() throws Exception{
…
}
public class demo {
public static void main(String[] args) {
int[] arr = new int[10];
System.out.println(arr[11]);
System.out.println("程序正常结束");
}
}
//代码实例
public void setAge(int age){
if(age<0 || age>180){
RuntimeExcetion e = new RuntimeException("不合理");
throw e;//人为抛出异常
}else{
this.age = age;
}
}
编写一个类, extends [Exception / RuntimeExcepion],并重写一参构造方法
定义方法时必须声明所有可能会抛出的exception
在进行异常的处理之后,在异常的处理格式中还有一个finally语句,那么此语句将作为异常的统一出口,不管是否产生
了异常,最终都要执行此段代码。
try{
...
return;//程序到这里是否已经结束?并没有
}catch(...){
...
}finally{
System.out.println("执行finally");
}
执行流程:
- 先计算返回值, 并将返回值存储起来, 等待返回
- 执行finally代码块
- 将之前存储的返回值, 返回出去;
需注意:
1.返回值是在finally运算之前就确定了,并且缓存了,不管finally对该值做任何的改变,返回的值都不会改变
2.finally代码中不建议包含return,因为程序会在上述的流程中提前退出,也就是说返回的值是try或catch中的值
3.如果在try或catch中停止了JVM(程序被关闭),则finally不会执行.【例如停电, 或通过“ System.exit(0); ”代码退出JVM:】
try{
int a = 10;
int b = 0;
System.out.print(a/b);
}catch(Exception e){
System.exit(Status:0);//Status可选值:0、1、2、3,0表示正常退出
}finally{
System.out.println("finally代码块执行");
}
Public Static int demo(){
int a = 10;
try{
return a;
}caatch(Exception e){
return null;
}finally{
a = 20;
}
}
Person p == neww Person();
try{
p.age = 18;
return p;
}catchh(Exception e){
return null;
}finally{
p.age = 28;
}
第一个代码块中,return中a的值为10
第二个代码块中,return中p的age的值为28
基本数据类型备份的是值,引用数据类型备份的是地址。注意数据类型的区分。