导言
-
面向对象思想理解:面向对象是一种程序设计规范,首先将万事万物当成对象来理解,他们都有各自的特征和行为方式,映射到程序设计层面就是每个对象都有表示各自的属性和功能,在我们处理问题时,建立不同的对象,不是为了实现一个步骤,而是描述一个事物在处理问题过程中的特性和行为。问题的解决通过对象间的交互完成。
-
面向过程思想理解:着眼于每一个具体步骤,用函数和方法一步步将问题解决,整个流程串联起来实现具体功能。
-
面向对象和面向过程的区别:
面向过程 :面向过程性能比面向对象高。 因为类调用时需要实例化,开销比较大,比较消耗资源,所以当性能是最重要的考量因素的时候,比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发。但是,面向过程没有面向对象易维护、易复用、易扩展。
面向对象 :面向对象易维护、易复用、易扩展。 因为面向对象有封装、继承、多态性的特性,所以可以设计出低耦合的系统,使系统更加灵活、更加易于维护。但是,面向对象性能比面向过程低。
另一个维度,当程序比较简单时面向过程设计更加简洁清晰,效率也高,但当功能越来越复杂,面向过程设计就愈发臃肿难以维护,所以面向对象思想更适合大型程序设计。 -
类和对象的区别
类是一组属性和行为的集合,是一个抽象的概念;
对象是该类事物的具体表现形式,是实体。
java三大特性(???修改)
1.封装, 将对象的数据和行为整合在一起,对外部只暴露方法接口,隐藏具体实现,只要方法不变,对象内部数据如何变化并不直接影响其他类
2.继承,拓展一个已有的类时,拓展后的新类具有所拓展类的全部属性和方法,在新类中,只需要提供适用于这个新类的新方法和数据域即可
3.多态,同一个对象的引用可以指向不同的类型,即父类接口可以指向子类对象,这样可以提高代码的拓展性,但父类引用不能指向子类的特有内容,也不能用子类引用指向父类对象。
- java对象的内存图
构造器
java中使用构造器创建对象并初始化部分状态;
补充的tip:
1.一个对象变量并没有真正包含一个对象,而仅仅是引用一个对象
2.对于包含多个文件的java程序编译,可以使用两个方法:
javac Classname*.java 通配符方法;
javac Classname.java 不会显示地编译该类使用的其他类文件,但是当编译器发现并没有需要的class文件时候,就会自动搜索并编译缺少的类文件。此外,编译器如果发现现有的.java文件比已有的.class文件新,就会自动重新编译这个文件。
构造器基本特性:
- 与类同名
- 每个类有一个以上的构造器
- 构造器可以有0,1或者多个参数
- 构造器没有返回值和返回值类型,连void也没有
- 总是伴随着new一起调用
注意事项:
- 系统会自动提供一个默认修饰符的无参构造方法,如果我们给了构造方法,无论有参数还是无参数,系统都不会默认提供了。
从编码规范角度看,建议坚持至少创建无参构造器 - 创建对象的时内存过程:
class Student {
private String name = "Franz";
private int age = 24;
public Student() {
name = "Leo";
age = 25;
}
}
class StudentDemo {
public static void main(String[] orgs) {
Student stu = new Student();
}
}
class文件加载到方法区,然后main方法进入栈区,创建指向对象的局部变量,然后在堆区创建新对象,其中的成员变量先被初始化为默认值,紧接着被赋予等号后初始值,然后才进入构造方法,被初始化为新的值,然后把堆内存的地址值赋值给stu变量。
- 有时候就算按常规设置了私有域域和共有域访问器方法,仍然可能破坏封装性,如
class Employee {
private Date hireDay;
public Date getHireDay() {
return hireDay;//这样外部获得该hireDay之后会调用Date额setTime方法改变该date
}
}
这种情况我们应该先对对象克隆,对象克隆是指存放在另一个位置上的对象副本。如果需要返回一个可变数据域的拷贝,就应该是使用clone.下面是修改后的代码
public Date getHireDay() {
return hireDay.clone();
}
- 被final标记的域必须在声明时初始化或者在构造器中初始化
- 构造器不能被重写,因为子类不能继承父类的私有域和构造方法。但是构造器可以重载。
重载和重写的关系:
重载overload:发生在编译时。在一个类里面,方法名字相同,参数类型或个数或顺序不同,则被视为重载,这是判断是否重载的核心。返回值类型可能不同,访问修饰符可能不同,检查异常范围可能不同。
重载严格意义上并不属于多态,重载的具体实现是:编译器根据不同的参数表,对同名函数的名称做修饰,然后这些同名函数就变成了不同的函数。对重载函数的调用,在编译期间就已经确定了,是静态的(注意!是静态的),因此,重载和多态无关。重写override:发生在运行时。重写是子类对父类被允许访问的方法实现过程进行重新编写,函数名和参数列表必须和父类方法相同。返回值范围小于等于父类,访问权限必须大于等于父类,抛出的异常范围小于等于父类,final、static声明的方法不能被重写,构造方法不能被重写,private声明的方法不能被重写。
真正和多态相关的是重写,当子类重写了父类中的函数后,父类的 指针,根据赋值给它不同的子类对象指针,动态的调用属于子类的该函数,这样在编译期间是无法确定的,只有在运行期间,才会把动态链接转变为直接引用
同名同签名的方法,父类方法如果加上了static修饰符,子类也应该加上static修饰符,这由于不涉及对象算不上重写,至于为什么?????
- 当一个变量被用来表示一个类的属性时候,才被规定为成员变量。变量的使用应该遵循影响范围越小越好原则,为了能被及时回收,防止夜长梦多。
- 子父类构造器的关系?
- 类加载过程,关于构造器、成员变量、静态代码块、代码块等?
静态域和静态方法
用于修饰类中被所有对象共享的变量或方法,它随着类的加载而加载,优先于对象存在。所以main方法是静态的,因为它被虚拟机调用,不需要创建对象。
注意点:
- 由于静态域和方法不单独属于任何对象,所以在静态方法中不能有this关键字,静态方法只能访问静态的成员变量或方法。
- 静态成员变量和方法存在方法区的静态区(成员变量存储于堆内存),当在堆中创建对象时候,不同对象中的静态引用指向同一个静态区的数据。
- 静态变量的生命周期同步于类,成员变量的生命周期同步于对象
关于main方法的补充:
public修饰符,因为需要被jvm直接调用,访问权限要最大;
static,因为不需要创建对象
void,方法的返回值是给调用者,jvm不需要main方法的调用值
string[] args,命令行参数,输入格式为java classname command line parameters, 一般我们没输入这个参数,所以系统接收的是一个长度为0的字符串数组。
补充,java方法参数是值传递还是引用传递的问题
首先看基本数据类型参数
public static void rise(double salary) {
salary = salary * 3;
}
public static void main(String[] args) {
double salary = 100;
rise(salary);
System.out.println(salary);
}
//输出为100
然后看对象引用作为参数时成员变量的变化
public static void growUp(Student student) {
student.setAge(student.getAge() + 1);
}
public static void main(String[] args) {
Student student = new Student(15);
System.out.println(student.getAge());
growUp(student);
System.out.println(student.getAge());
}
//输出为15.0,16.0.
再看最后一种情况
public static void swamp(Student a, Student b) {
Student temp = a;
a = b;
b = temp;
System.out.println(a.getAge()+" "+b.getAge());
}
public static void main(String[] args) {
Student a = new Student(15.5);
Student b = new Student(16.5);
swamp(a,b);
System.out.println(a.getAge()+" "+b.getAge());
}
//输出结果
16.5 15.5
15.5 16.5
结论一:方法不能修改基本数据类型的参数;
结论二:传入对象引用作为参数时能够改变对象的状态,因为方法参数和传入的对象引用同时指向同一个对象;
结论三:传入对象引用并不能被改变指向
根本结论:java语言是按值调用,方法得到的是所有参数值的一个拷贝,方法不能修改传递给它的任何参数变量的内容。
补充,java内存图解
包
访问其他包的共有类两种方法,类前加前缀或者导包;
- 注意号只表示导入了单个包中的所有类,不能使用import java.或者import java..表示导入了以java为前缀的所有包。
- 当有重名的类时,如同时import了java.util.和java.sql.这就需要再加句import java.util.Date表示使用的是该包下的Date,如果两个都想要,那么在类前缀前加包名。
- 静态导入,import static java.lang.System.*,这样就能在程序中使用System类的静态内容,如out.println();此外,还可以导入特定的方法或方法域,import static java.lang.System.out,这个用的很少。
- 如果类文件没有指定package语句,就会被放到一个默认包中
- 编译器编译java文件,而解释器加载.class文件。使用编译命令时需要指定完整的包名,如javac com/***/****/Student.java,此时编译器还会自动查找同类名下使用到的其他文件并编译。
代码块
- 局部代码块 在方法中出现,限定变量声明周期,及时释放无用变量,提高内存利用率
- 构造代码块 在类中方法和构造函数之外出现,用于对每个对象进行与构造方法无关的初始化,每次创建对象都会执行,并且在构造方法前执行。
- 静态代码块 与之前两种形式上区别就是多了个static,对类进行初始化,在所有代码块中最先执行,但只执行一次。在main方法所在的类中,该类的静态代码块仍然领先于main方法执行,所以方法加载是在类加载之后的。
网友评论