JVM内存分配: 方法区, 栈, 堆,常量池
怎么得到一个对象
1.拉姆达表达式
Lambda 表达式(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,
直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。
Java 8 引入的 Lambda 表达式的主要作用就是简化部分匿名内部类的写法。
能够使用 Lambda 表达式的一个重要依据是必须有相应的函数接口。所谓函数接口,是指内部有且仅有
一个抽象方法的接口。
Lambda 表达式的另一个依据是类型推断机制。在上下文信息足够的情况下,编译器可以推断出参数表
的类型,而不需要显式指名。
2.1 函数式接口
@FunctionalInterface , 函数式接口 : 接口内部,必须的只有一个抽象方法。
在接口中可以使用default修饰方法,那么该方法必须有方法体。
// annotation : 注解
@FunctionalInterface // 函数式接口 : 接口内部必须只有一个抽象方法
public interface AInterface {
public abstract int sum(int x, int y);
}
//@FunctionalInterface : 好处在于写错可以有提示
interface BInterface{
// 判断年龄是否大于18
boolean isBigPeople(int age); // 保证接口里只有一个方法,就是一个函数式接口
}
@FunctionalInterface
interface CInterface{
// 输出一句话: name + "," + word
void sayHi(String name, String word);
}
@FunctionalInterface
interface DInterface{
// 产生一个随机整数
int randomInt();
//java1.8开始,接口中,可以使用default修饰方法,写方法的实现
//default 修饰的方法,必须有方法体
default int randomInt(int bound){
Random random = new Random();
int data = random.nextInt();
return data;
}
}
interface EInterface{
// 产生一个随机整数
int randomInt();
int randomInt(int bound);
}
/*
@FunctionalInterface : 只能修饰interface
abstract class B{
public abstract int add(int x);
}
*/
2.2 拉姆达表达式的使用
先了解一定的语法规则,后期在使用的时候,在逐渐熟悉更多的使用方式。
class F{
//通过调用AInterface中的sum方法,求两个数的和
int k(AInterface a ,int x, int y){
return a.sum(x, y);
}
boolean b (BInterface b, int age){
return b.isBigPeople(age);
}
void c(BInterface b, DInterface d){
int r = d.randomInt();
System.out.println("年龄:"+r);
boolean b1 = b.isBigPeople(r);
if(b1){
System.out.println("成年人");
}else{
System.out.println("未成年");
}
}
}
import java.util.Random;
public class TestLambda {
public static void main(String[] args) {
//lambda表达式的使用 , 对应的接口要符合函数式接口的特征
//函数的参数格式,(可以省略函数名字,可以省略参数类型), -> {函数体}
//如果是无参的函数,那么就直接写()
//如果是有参的函数,就写(参数名)
AInterface aInterface = (a,b) -> {
//内部把a , b 当接口中方法定义的类型使用
/*if(a){ -- a 是int类型,参数接口中的类型使用
return 0;
}*/
return a + b;
};
aInterface.sum(4,5);
BInterface bInterface = (h) -> {
return h >= 18;
};
bInterface.isBigPeople(19);
CInterface cInterface = (name, word) -> {
System.out.println(name+","+word);
};
cInterface.sayHi("alice","欢迎光临");
/*DInterface dInterface = () -> {
return (int) (Math.random()*100);
};*/
DInterface dInterface = () -> {
Random random = new Random();
return random.nextInt();
};
System.out.println(dInterface.randomInt());
//计算两个数的和,输出和
int he = ((AInterface)(x,y) -> {return x + y;}).sum(3,5);
System.out.println("he:"+he);
// *** 方法调用的时候: 参数的类型,参数的个数,参数的返回值
//*** 方法的定义: 方法签名(方法的修饰符,返回值,方法,参数)
//调用F中的k方法
F f= new F();
int he1 = f.k((a,b) -> {return a + b;}, 4,5);
//调用F中的b方法
System.out.println("he1:"+he1);
boolean b1 = f.b((m)->{return m >= 18;}, 20);
// 调用F中的c方法
f.c((n)->{return n >= 18;}, ()->{
return (int) (Math.random() * 100 + 1);});
}
}
2.== 和 equals的区别
-
== , 基本数据类型,判断数据值是否相等
-
== , 引用类型,判断引用类指向的地址是否相等,即是否为同一个对象。
-
equals是父类Object中提供的的一个equals方法,用于制定两个对象是否相等的比较规则。
Object中的equals默认是比较两个对象的地址是否相同。
-
子类重写父类的equals方法,自定义比较规则:
比如: 判断两个点是否相同,可以判断两个点的x位置和y位置同时相等,则两个点相同。
-
如果两个对象比较equals为true ,那么这依然不能说明是否为同一个对象。
3.Object类型:所有类的父类。
import java.lang.Object; // 省略了
// 一般省略: extends Object
// Object 是所有类的父类:该类中封装了常用的属性和方法
public class Point extends Object{
int x;
int y;
public Point(){
super(); // 省略
}
public void up(){
y++;
}
}
class TestPoint{
public static void main(String[] args) {
Class pointClass = Point.class;
Point p = new Point();
Class pClass = p.getClass();
//可以重写toString
//*** toString: 显示成员变量的值
String str = p.toString(); // 继承的toString
System.out.println(str); //day5.Point@3ac3fd8b
//*** 输出语句,输出某个引用的时候,本质上是调用toString方法。
System.out.println(p); //day5.Point@3ac3fd8b
//可以重写hashCode
int code = p.hashCode(); // 继承了hashCode
// 一般会重写euqals方法。
// ** 自定义比较规则(一般比较属性值是否相同。)
boolean b = p.equals(p); // 继承了父类的equals方法。
}
}
Objects类型的使用:
import java.util.Objects;
public class TestOjects {
public static void main(String[] args) {
Shape s = new Shape();
s.x = 5;
s.y = 10;
Shape s1 = new Shape();
s1.x = 5;
s1.y = 10;
boolean flag = Objects.equals(s,s1); // -- ··调用到Shape类型的equals方法。
System.out.println("s -- > s1:"+flag); // true
Point p = new Point();
p.x = 10; p.y = 10;
Point p1 = new Point();
p1.x = 10; p1.y = 10;
boolean b = Objects.equals(p,p1); // -- 调用到Point类型的equals方法
System.out.println("p -- > p1:" + b); // false(Point类型没有重写equals方法,使用Object中的equals方法。)
}
}
4.重写equals方法
从Object类中基础的equals方法,不满足子类的使用的时候,可以重写该方法。
重写equals : equals的比较,一般是比较两个对象的成员变量的值是否相等。
public class Shape {
int x;
int y;
public Shape() {}
//public String toString(){
// //return Shape.class + " (" + x + "," + y + ")";
// return this.getClass() + "(" + x + "," + y + ")";
//}
@Override
public String toString() {
return "Shape{" +
"x=" + x +
", y=" + y +
'}';
}
// 重写equals:equals的比较,一般是比较两个对象的成员变量的值是否相等
// 如果两个对象的x相等,那么euqals结果为true,否则为false
public boolean equals(Object o){ // 向上造型
//如果是null,说明不等
if(o == null){
return false;
}
//如果类型不同,说明不等
if(this.getClass() != o.getClass()){
return false;
}
//如果是自己,说明相等
if(this == o){ // 判断的是引用地址是否相等,如果相等,说明是同一个对象
return true;
}
//如果类型相同,不是自己,判断属性值是否相等
if(o instanceof Shape){
Shape shape = (Shape) o; // 强制类型转换
if(shape.x == this.x && shape.y == this.y){ // 比较规则
return true;
}
}
return false; //不符合上面的条件,说明不相等
}
}
class TestShape{
public static void main(String[] args) {
Shape s1 = new Shape();
s1.x = 5;
s1.y = 10;
Shape s2 = new Shape();
s2.x = 5;
s2.y = 10;
System.out.println("toString");
System.out.println(s1);
System.out.println(s2);
System.out.println("==");
System.out.println(s1 == s1); // true
System.out.println(s1 == s2); // false
System.out.println("equals");
System.out.println(s1.equals(s1)); // ture
System.out.println(s1.equals(s2)); // true
System.out.println("==========================================");
String a1 = "a";
String a2 = "abc";
String a3 = new String("a");
String a4 = new String("abc");
String a5 = "abc";
System.out.println(a1 == a2); // false 不同对象
System.out.println(a1 == a3); // false 不同对象
System.out.println(a2 == a3); // false 不同对象
System.out.println(a2 == a4); // false 不同对象
System.out.println(a2 == a5); // true 相同对象(字符串常量池规则)
System.out.println(a2.equals(a3)); // false 数据值不同
System.out.println(a2.equals(a4)); // true 数据值相同 重写后的equals方法比较数据值
}
}
5.静态代码块
类中的代码块可以使用static修饰,则被称为静态代码块
public class StaticBlockDemo {
public static void main(String[] args) {
//** 静态代码块,优先于静态方法的调用
//*** 如果有什么代码,需要在类加载的时候,就执行,把这个代码放在静态代码块中(静态代码块只执行一次。)。
Foo.show(); // -- 通过类名 ,直接调用静态方法
//** 静态代码块,优先于构造函数执行
//*** 如果有代码,希望在创建对象之前(构造函数调用之前),都要执行,可以使用非静态代码块(非静态代码块执行多次)。
Foo f = new Foo();
f.print();
//Foo f1 = new Foo();
}
}
// 加载顺序: 静态代码块 -> 静态方法 -> 非静态代码块 -> 构造器函数 -> 非静态方法
class Foo{
public Foo(){
System.out.println("构造器函数");
}
static {
System.out.println("这个是静态代码块");
}
{ //经过编译,这个内容,就放在了构造函数内部代码之前了
System.out.println("这个是非静态代码块");
}
public void print(){
System.out.println("这个是普通方法");
}
public static void show(){
System.out.println("这个是静态方法"); // 静态的东西不属于对象,而属于类
}
}
6.面向对象特征——封装
import java.util.Objects;
public class Student {
private int age;
private String hobby;
private String name;
private String sex;
//自动生成get/set方法
//** set :给成员变量赋值,set方法有参数,无返回值
//** get :获取成员变量的值,get值方法无参数,有返回值
//** 方法名的特征: get属性名首字母大写,set属性名首字母大写
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age
&& Objects.equals(hobby, student.hobby) // Objects.equals(引用1, 引用2) -- 工具方法,判断是否相等。
&& Objects.equals(name, student.name)
&& Objects.equals(sex, student.sex);
}
@Override
public int hashCode() {
return Objects.hash(age, hobby, name, sex); // Objects.hash -- 工具方法,计算要给hash值。
}
}
class TestStudent{
public static void main(String[] args) {
Student stu = new Student();
stu.setAge(20);
stu.setHobby("看书");
stu.setName("tom");
stu.setSex("男生");
System.out.println("-----------获取成员变量值-----------");
System.out.println(stu.getName() + ", " + stu.getSex() + "," + stu.getHobby() + " ," + stu.getAge());
}
}
7.面向对象三大特性—继承
-
A类通过extends关键字,继承B类,Java是中是单继承,一个子类只能有一个父类,一个父类可以
有多个子类
-
继承能够提高代码的重用性
8.面向对象三大特性—多态
-
对象是多种状态的。
-
父类的引用指向子类的对象
Father s=new Son();
//打印机类(父类)
public class Printer {
public void print(){
}
}
//三个打印机类的子类
class Printer3D extends Printer{
public void print(){// 父类方法的重写
System.out.println("3D打印机正在打印");
}
}
class PrinterBlack extends Printer{
public void print(){
System.out.println("黑白打印机正在打印");
}
}
class PrinterColor extends Printer{
public void print(){
System.out.println("彩色打印机正在打印");
}
}
-
父类的引用指向子类的对象
Father s=new Son();
//打印机类(父类)
public class Printer {
public void print(){
}
}
//三个打印机类的子类
class Printer3D extends Printer{
public void print(){// 父类方法的重写
System.out.println("3D打印机正在打印");
}
}
class PrinterBlack extends Printer{
public void print(){
System.out.println("黑白打印机正在打印");
}
}
class PrinterColor extends Printer{
public void print(){
System.out.println("彩色打印机正在打印");
}
}