《Effective Java》第二版总结

2023-10-28

《Effective Java》主要给了78条编码建议,指导,方便开发者开发出,高效,稳定,健壮,设计优良的程序。下面看一下这78条建议。

创建和销毁对象
1、考虑用静态工厂方法代替构造器


/*
    为了让客户端获取他自身的一个实例,最常用的方法就是提供一个公有的构造器。
    
    还有一种方法,类可以提供一个公有的静态工厂方法,它只是返回类的实例的静态方法。
*/



//一个简单的单例
public class Singleton {
	private static Singleton singleton;
	
	private Singleton() {
		singleton=new Singleton();
	}
	
	public static Singleton getSingleton() {
		return singleton;
	}

}

2、遇到多个构造器参数时要考虑用 建造者模式
当一个类有多个构造器参数时,该怎么创建?

  • 重叠构造器
  • java beans
  • 建造者模式
//重叠构造器
public class User {
	
	private String name;
	private String password;
	private String id;
	private String phonenumber;
	private String desc;
	private String emil;

	public User(String name) {
		this(name, null);
	}

	public User(String name, String password) {
		this(name, password, name, null);
	}

	public User(String name, String password, String id) {
		this(name, password, id, password, null);
	}
	
	public User(String name, String password, String id, String phonenumber) {
		this(name, password, id, phonenumber, id,null);
	}
	
	public User(String name, String password, String id, String phonenumber, String desc) {
		this(name, password, id, phonenumber, desc,null);
	}

	public User(String name, String password, String id, String phonenumber, String desc, String emil) {
		this.name = name;
		this.password = password;
		this.id = id;
		this.phonenumber = phonenumber;
		this.desc = desc;
		this.emil = emil;
	}
}
//不易扩展 当有许多参数的时候,客户端代码会很难编写,很难阅读
//java beans
public class User {
	
	private String name;
	private String password;
	private String id;
	private String phonenumber;
	private String desc;
	private String emil;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getPhonenumber() {
		return phonenumber;
	}
	public void setPhonenumber(String phonenumber) {
		this.phonenumber = phonenumber;
	}
	public String getDesc() {
		return desc;
	}
	public void setDesc(String desc) {
		this.desc = desc;
	}
	public String getEmil() {
		return emil;
	}
	public void setEmil(String emil) {
		this.emil = emil;
	}
}

//多线程情况下要考虑线程安全


//建造者模式
public class User {
	
	private String name;
	private String password;
	private String id;
	private String phonenumber;
	private String desc;
	private String emil;
	
	
	public static class Builder() {
		private String name;
		private String password;
		private String id;
		private String phonenumber;
		private String desc;
		private String emil;
		
		public Builder name(String m) {
			this.name=m;
		}
		
		public Builder password(String m) {
			this.password=m;
		}
		
		public Builder id(String m) {
			this.id=m;
		}
		
		public Builder phonenumber(String m) {
			this.phonenumber=m;
		}
		
		public Builder desc(String m) {
			this.desc=m;
		}
		
		public Builder emil(String m) {
			this.emil=m;
		}
		
		public User build() {
			return new User(this);
		}
	}
	
	private User(Builder builder) {
		name=builder.name;
		password=builder.password;
		id=builder.id;
		phonenumber=builder.phonenumber;
		desc=builder.desc;
		emil=builder.emil;
	}
	
	
}


//如果类的构造器中有多个参数时 建议使用建造者模式  容易扩展 也不存在线程安全问题


3、用私有构造器或者枚举类型强化 单例 属性

//简单的单例
public class Singleton {
	private static Singleton singleton;
	
	private Singleton() {
		singleton=new Singleton();
	}
	
	public static Singleton getSingleton() {
		return singleton;
	}

}

不考虑线程安全,懒加载等问题,这样存在两个风险

  • 可以通过反射调用单例类的构造方法创建实例
  • 可以通过序列化,反序列化 来获得 单例的实例

使用枚举类型实现单例,可以有效避免这两个问题
推荐使用下面这种写法

public enum Singleton {
	INSTANCE;
	
	public void doSomething() {
		
	}

}

//可以有效避免 反射和序列化反序列 创建对象 问题

4、通过私有构造器强化不可实例化的能力
有些类(例如工具类)不希望被实例化,实例对他没有任何意义。
可以通过如下方法避免类被实例化


public class Utils {
	
	private Utils() {
		throw new AssertionError();
	}

}

5、避免创建不必要的对象

一般来说,最好能重用对象而不是在每次需要的时候就创建一个相同功能的新对象。

6、消除过期的对象引用

消除过期的对象引用,避免程序出现内存泄露,进而导致OOM。

7、避免使用终结方法

终结方法(finalizer)通常是不可预测的,也是很危险的,一般情况下是不必要的。

终结方法的缺点不能保证会被及时执行。从一个对象变得不可达开始,到它的终结方法被执行,所花费的这段时间是任意长的。

对于所有对象都通用的方法
8、覆盖equals时请遵守通用约定

自反性;对于任何非null的引用值x,x.equals(x)都返回true。

对称性;对于任何非null的引用值x和y,当且仅当y.equals(x)返回true时,x.equals(y)必须返回true。

传递性;对于任何非null的引用值x,y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也必须返回true。

一致性;对于任何非null的引用值x和y,只要equals()的比较操作在对象中所用的信息没有更改,多次调用x.equals(y)就会一致的返回true或false。

非空性:对于任何非null的引用值x,x.equals(null)必须返回false。

9、覆盖equals是总要覆盖hashcode

相等的对象必须有相同的散列码

3点约定:

1)在java应用执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对这同一对象调用多次hashCode方法都必须始终如一地同一个整数。在同一个应用程序的多次执行过程中,每次执行该方法返回的整数可以不一致。

2)如果两个对象根据equals(Object)方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。

3)如果两个对象根据equals(Object)方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法没必要产生不同的整数结果。但是程序猿应该知道,给不同的对象产生截然不同的整数结果,有可能提高散列表(hash table)的性能。



因此,覆盖equals时总是要覆盖hashCode是一种通用的约定,而不是必须的,如果和基于散列的集合(HashMap、HashSet、HashTable)一起工作时,特别是将该对象作为key值的时候,一定要覆盖hashCode,否则会出现错误。那么既然是一种规范,那么作为程序猿的我们就有必要必须执行,以免出现问题。


10、始终要覆盖tostring

需要覆盖 toString方法,返回对象中包含的所有值得关注的信息。 程序员以这种方式来产生真短消息。

建议用 编译器自动生成的tostring,  如果其他要求,可以自己定制。

11、谨慎的覆盖clone
12、考虑实现Comparable接口

compareTo方法:

将这个方法与指定的对象进行比较,当对象小于,等于或大于指定对象的时候,分别返回一个负整数,零,或者正整数。如果由于指定对象的类型二无法与该对象进行比较,则抛出
ClassCastException.

举个例子

/*
 
 大整数排序
 
 题目描述

对N个长度最长可达到1000的数进行排序。

输入描述:

输入第一行为一个整数N,(1<=N<=100)。 
接下来的N行每行有一个数,数的长度范围为1<=len<=1000。 
每个数都是一个正数,并且保证不包含前缀零。

输出描述:

可能有多组测试数据,对于每组数据,将给出的N个数从小到大进行排序,输出排序后的结果,每个数占一行。

示例

输入: 
3 
11111111111111111111111111111 
2222222222222222222222222222222222 
33333333

输出: 
33333333 
11111111111111111111111111111 
2222222222222222222222222222222222

 */





import java.util.*;


public class Main{

    public static void main(String[] args) {

        Scanner scanner=new Scanner(System.in);

        int n=scanner.nextInt();


        List<String> list=new ArrayList<>();

        int index=0;
        while (scanner.hasNext()) {
            list.add(scanner.next());

        }

        Collections.sort(list,new Comparator<String>() {

            @Override
            public int compare(String o1, String o2) {
            //先比较长度,长度长的数大
            //如果大,返回1,小返回-1
                if(o1.length()-o2.length()>0) return 1;
                if(o1.length()-o2.length()<0) return -1;
                else {
                    if (Integer.valueOf(o1.charAt(0))>Integer.valueOf(o2.charAt(0))) {
                        return 1;
                    }
                    if (Integer.valueOf(o1.charAt(0))<Integer.valueOf(o2.charAt(0))) {
                        return -1;
                    }
                    else {
                    //如果长度相等,从第一位开始比较,若想等 依次向后比较
                        int i=1;
                        while (i<o1.length()) {

                            if (Integer.valueOf(o1.charAt(i))>Integer.valueOf(o2.charAt(i))) {
                                return 1;
                            }
                            if (Integer.valueOf(o1.charAt(i))<Integer.valueOf(o2.charAt(i))) {
                                return -1;
                            }
                            else {
                                i++;
                            }


                        }


                    }


                }
                return 0;

            }
        });






        for (int i = 0; i <list.size(); i++) {

            System.out.println(list.get(i));
        }


    }





}


类和接口
13、使类和成员的可访问性最小化

尽可能地使每个类或者成员不被外界访问。

可以有效地降低耦合,使得各模块可以独立 开发,测试,修改,优化和理解。

14、在公有类中使用访问方法而非公有域

//公有域不应该直接暴露数据域
public class Point {
	
	public int x;
	public int y;

}
//应该使用私有域和公有设值(setter) 方法
public class Point {
	
	private int x;
	private int y;
	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
	public int getY() {
		return y;
	}
	public void setY(int y) {
		this.y = y;
	}

}

15、使可变性最小化

不可变的类比可变的类更加易于设计,实现和使用。他们不容易出错,而且更加安全。

为了使类成为不可变,要遵循下面五条规则。

1、不要提供任何会修改对象状态的方法。

2、保证类不会被扩展。

3、使所有域都是final的。

4、使所有域都成为私有的。

5、确保对于任何可变组件的互斥访问。

16、复合优先于继承

当只有子类和父类确实存在子类型关系时。使用继承才是最恰当的。

如果子类和父类处在不同的包,并且父类并不是为继承而设计,那么继承会导致脆弱性。

继承打破了 封装性,子类依赖其父类中特定功能的实现细节。 父类的实现可能会随着发行版本的不同而有所变化,如果真的发生了变化,子类可能会遭到破坏,即使他的代码完全没有改变。

17、要么为继承而设计,并提供文档说明,要么就禁止继承

该类的文档必须精确的描述覆盖每个方法所带来的影响。

要么设计成final类 禁止继承。

18、接口优先于抽象类

Java 单继承多实现。

接口通常是定义允许多个实现的类型的最佳途径。

19、接口只用于定义类型

接口应该只被用来定义类型,他们不应该被用来导出常量。

20、类层次优先于标签类

标签类过于冗长,容易出错,并且效率低下。

21、用函数对象对象表示策略
22、优先考虑静态成员类

当必须使用静态内部类时,建议使用静态内部类。

某些情况还是要多考虑。

泛型
23、请不要再新代码中使用原生态类型

如果使用原生态类型,就失掉了泛型在安全性和表述性方面的所有优势。

屏蔽掉了编译错误,可能会出现运行时错误,抛出 ClassCastException。

24、消除非受检警告

要尽可能消除每一条非受检警告。

如果无法消除非受检警告,同时可以证明引起警告的代码是类型安全的,就可以在尽可能小的范围中,用@SuppressWarnings("unchecked")注解禁止该警告。要用注释把禁止改警告色原因记录下来。

25、列表优先于数组

建议优先使用列表泛型,可以在编译期间检查代码参数合法性。避免运行时错误。

26、优先考虑泛型

使用泛型比使用类型转换更加安全,也更加易读。

27、优先考虑泛型方法

泛型方法像泛型一样,使用方法比要求客户端转换输入参数并返回值的方法来得更加安全,也更加容易。

28、利用有限制通配符来提升 API 的灵活性
29、优先考虑类型安全的异构容器

枚举和注解
30、用enum代替常量

public enum Color {
	RED,YELLOW,BLACK,GREEN
}
public enum Color {

	//数值是瞎编的 a ~
	RED(0,0,0,0),
	YELLOW(1,1,1,1),
	BLACK(1,0,1,0),
	GREEN(1,0,1,1);
	
	private int a;
	private int r;
	private int g;
	private int b;
	
	private Color(int a, int r, int g, int b) {
		this.a = a;
		this.r = r;
		this.g = g;
		this.b = b;
	}
	
	public void doSomething() {
		
	}
}

相比int常量,枚举易读,更安全,也更强大。

31、用实力域代替序数
32、用EnumSet代替位域

EnumSet 简洁 ,性能高

33、用EnumMap 代替序数索引

最好不要用序数索引数组,而要使用  EnumMap 

34、用接口模拟可伸缩的枚举

虽然无法编写可扩展的枚举类型,却可以通过编写接口以及实现该接口的枚举类型。对它进行模拟。

35、注解要优先于命名模式

命名模式 JDK1.5之前的东西,现在使用的基本都是注解。

36、坚持是有override注解

如果想要在每个方法声明中使用 override 注解覆盖父类声明,编译器会替你防止大量的错误。

37、用标记接口定义类型

标记接口  是没有包含方法生命的接口,只是指明 一个类实现了具有某种属性的接口,例如Serializable

如果想要定义类型,一定要使用接口。

方法
38、检查参数有效性

每当编写方法或者构造器时,应该考虑它的参数有哪些限制,应该把这些限制写到文档中,并且在每个方法体的开头处,通过显示的检查实施这些限制。

39、必要时进行保护性拷贝
40、谨慎的设计方法签名

谨慎的选择方法的名称
不要过于追求便利的方法
避免过长的参数列表

41、慎用重载

一般情况下,对于多个具有相同参数数目的方法来说,应该尽量避免重载方法。

42、慎用可变参数

	
	//main函数
	public static void main(String...args) {
		
	}
	
	
	public static int sum(int... args) {
		int sum=0;
		for (int i = 0; i < args.length; i++) {
			sum=sum+args[i];
		}
		
		return sum;
	}

//可变参数的设计初衷就是为了 方便  printf和 反射机制的使用

//在定义参数数目不定的方法时,可变参数是一种很方便的方式,但是他们不应该被过度滥用。如果使用不当,会产生混乱的结果。

43、返回零长度的数组或者集合,而不是null

	private List<String> mTitles=Arrays.asList("帖子","好友","消息");
	
	public List<String> getTitles(List<String> list){
		if(list.size() == 0) {
			return null;
		}else {
			
			return list;
		}
		
	}

//应该返回零长度的数组或者集合


	private List<String> mTitles=Arrays.asList("帖子","好友","消息");
	
	public List<String> getTitles(List<String> list){
		if(list.size() == 0) {
			return new ArrayList<>();
		}else {
			
			return list;
		}
		
	}
	
	// 返回数据或集合的方法 不应该返回null 而应该返回一个零长度的数组或集合
	
	//返回null容易出错 因为编写客户端程序的程序员可能会忘记写这种专门的代码来处理null返回值


44、为所有导出的API元素编写文档注释

要为API编写文档,文档注释是最好,最有效的途径。

通用程序设计
45、将局部变量的作用域最小化

将局部变量的作用最小化,可以增强代码的可读性和可维护性,并降低出错的可能性。

46、for-each 循环优先于传统的for循环

for-each 循环在简洁性和预防bug方面有着传统的for循环无法比拟的优势,而且没有性能损失,应该尽可能的使用 for-each 循环。

47、了解和使用类库

总而言之,不要重复造轮子,如果你要做的事情是看起来十分常见的,有可能类库中某个类已经完成了这样的操作,如果确实是这样,就使用现成的,如果不清楚是否存在这样的类,就去查一查。

48、如果需要精确的答案,请避免使用float和double

如果需要精确答案,请使用 BigDecimal

49、基本类型优先于装箱基本类型

当可以选择的时候,基本类型要优先于装箱基本类型。基本类型更加简单,也更加迅速。

50、如果其他类型更合适,则尽量避免使用字符串

如果可以使用更加合适的数据类型,或者可以编写更加适当的数据类型,就应该避免用字符串来表示对象。

若使用不当,字符串会比其他的类型更加笨拙,更不灵活,速度更慢,也更容易出错。

51、当心字符串链接的性能

为连接n个字符串而重复使用字符串链接操作符,需要n的平方级时间。

不要使用字符串连接操作符来合并多个字符串,除非性能无关紧要。

相反,应该使用 StringBuilder的 append方法。

52、通过接口引用对象

53、接口优先于反射

54、谨慎的使用本地方法

使用本地方法提高性能的做法是不值得提倡的。在这些年间,VM已经变得很快了。

是用本地方法有一些严重的缺点,因为本地语言是不安全的,是用本地方法的应用程序也不再能面授内存毁坏错误的影响

55、谨慎的进行优化

没有绝对清晰的优化方案之前,请不要进行优化。

在每次视图做优化之前和之后,要对性能进行测量。

试着使用性能剖析工具

检查所选择的的算法,再多的底层优化也无法弥补算法的选择不当。

56、遵守普遍接受的命名惯例

团队应该有统一的编码规范,每个成员都需要遵守。方便后续团队开发。

异常
57、只针对异常的情况下才使用异常

因为异常机制的 设计初衷是用于不正常的情形,所以很少会有jvm实现试图进行优化。

把代码 放在 try-catch 块中反而阻止了现代jvm实现本来可能要执行的某些特定优化。

实际上,现代jvm实现上,基于异常的模式比标准模式要慢的多。

总而言之,异常是为了在异常情况下使用而设计的,不要将它们用于普通的控制流,也不要编写迫使他们这么做的API。

58、对可恢复的情况使用受检异常,对编程错误使用运行时异常

如果期望调用者能够适当的进行恢复,对于这种情况,应该使用受检异常。

通过抛出该受检的异常,强迫调用者在一个catch字句中处理该异常。

59、避免不必要的使用受检异常

过分使用受检异常会使API使用起来非常不方便。

如果一个方法抛出一个或多个受检异常,调用该方法的代码就必须在一个或者多个catch快中处理这些异常,或者它必须声明它抛出这些异常,并让他们传播出去,无论那种方法,都给程序员增添了不可忽视的负担。

60、优先使用标准的异常

优先使用标准的异常,有如下好处:
1、它使你的API更加容易学习和使用,因为它与程序员 已经熟悉的习惯用法是一致的。

2、对于用到这些API的程序来说,它的可读性更好,因为他不会出现很多程序员不熟悉的异常。

3、异常类越少,意味着 内存印迹(footprint)就越小,装载这些类的时间开销也越少。

61、抛出与抽象相对应的异常


62、每个方法抛出的异常都要有文档

如果没有为抛出的异常建立相应的文档,其他人很难或者根本不可能使用你的类和接口。

63、在细节信息中包含 能捕获失败的类型

当程序由于未被捕获的异常而失败的时候,系统会自动打印出该异常的堆栈轨迹,在堆栈轨迹中包含该字符串的堆栈表示法,即它的 tostring 方法的调用结果,他通常包含异常的类名,紧随其后的是细节信息。

因此,异常类型的toString 方法应该尽可能多的返回有关失败原因的信息。

64、努力使异常保持原子性
65、不要忽略异常

不管异常代表了可预见的异常条件,还是编程错误,用空的catch快忽略他,将会导致程序在遇到错误的情况下悄然的执行下去,然后,有可能在将来的某个点上,当程序不能容忍与错误源明显相关的问题时,它就会失败。

正确的处理异常可以彻底挽回失败,只要将异常传播给外界,至少会导致程序会迅速失败,从而保留了有助于调式该失败条件的信息。

并发
66、同步访问共享的可变数据

当某个数据需要被多个线程共享访问时,需要进行同步。

如果没有同步,就无法保证一个线程所做的修改可以被另一个线程获知。 即内存可见性。

67、避免过度同步

要限制同步区域的工作量 ,不要多层同步。避免过度同步提高程序性能。

68、executor和task 优先于线程

当项目中线程的数量很多时,推荐使用线程池。

因为手动创建和销毁线程耗费性能,不便于管理。

在这里插入图片描述
在这里插入图片描述

69、并发工具优先于 wait和notify

当遇到并发问题时,优先使用 java并发工具 。java.util.concurrent

java.util.concurrent  主要有三类:
Executor Framework 线程池
Concurrent Collection 并发集合
Synchronizer 同步器

70、线程安全的文档化

每个类应该有说明或者线程安全注解,说明他的线程安全属性。

71、慎用延迟初始化

大多数域应该正常地进行初始化,而不是延迟初始化。

为了达到性能的目标,可以使用相应的延迟初始化方法。

72、不要依赖于线程调度器

73、避免使用线程组(Thread Group)

线程组 设计初衷主要是 为隔离 applet,  在其他地方很少见到。

如果你正在设计的一个类需要处理线程的逻辑组,或许应该使用线程池executor。

序列化
74、谨慎的实现Seriaizable 接口

75、考虑使用自定义的序列化形式

76、保护性地编写 readObject方法

readObject 方法实际上相当于另一个公有的构造器,如同其他构造器一样,它也要求注意同样的所有注意事项。狗在其必须检查其参数的有效性,并且在必要的时候对参数进行保护性拷贝。

77、对于实际控制,枚举类型优先于 readResolve

78、考虑用序列化代理代替序列化实例

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

《Effective Java》第二版总结 的相关文章

随机推荐

  • maven的版本号version的总结及理解

    maven的版本号version的总结及理解 本文目的 接上一篇 maven的基本概念介绍 大概了解maven里边的坐标 仓库的概念 其中 坐标里有版本号
  • 什么是接口

    概念 接口是更加彻底的抽象 接口中全部是抽象方法 接口是不能直接创建对象的 从JDK8之后 接口中不再只是抽象方法 接口还可以有默认方法 也就是实例方法 和静态方法了 还包含了私有实例方法和私有静态方法 在JDK8之前 接口中的成分包含 抽
  • 关于微信将默认打开网页快照页模式进行基础浏览,解决授权方案

    解决方案 如需解决请留言
  • 【跑实验06】os包的理解?如何提取图片的名称?如何遍历一个文件夹,提取里面的图像名称?如何提取图片名称中的特定部分?代码错误地方修改;

    文章目录 一 os包的理解 1 1 文件和目录操作 1 2 进程管理 1 3 环境变量 1 4 路径操作 二 如何提取图片的名称 三 遍历一个文件夹 提取里面的图像名称 四 如何提取图片名称中的特定部分 五 代码报错修改 一 os包的理解
  • IIC知识整理以及ADS1115

    什么是IIC IIC Inter Integrated Circuit 通常发音为 I squared C 是多主 多从 分组交换 单工的串行总线 通常用于处理器或微控制器与低速外围器件的短距离通信连接 这个通信协议是由 NXP半导体的前生
  • STM32HAL学习笔记六-定时器之正交解码

    STM32HAL学习笔记六 定时器之正交解码 本次实验使用STM32F103ZET6开发板的TIM2对带霍尔编码器的减速电机进行计数 然后将输出计数值通过串口打印 因此本次实验是在实验二的基础上进行修改 参考 https blog csdn
  • easyPOI导入导出之下拉框

    说起easypoi相信大家经常会用 因为在数据导入导出时 常用的也就是 xls文件进行上传下载 一般需要下载一个模板 然后再上传 在一次开发中 甲方提到一个需求 需要带下拉框的excel 于是我摸索了下 做个简单的笔记 如下 import
  • 如何创建属于你自己的域名邮箱

    1 打开腾讯云 gt 域名管理 gt 域名注册 gt 注册了一个域名网址 2 点击腾讯域名邮箱 3 创建域名邮箱 即输入您注册的域名网址 4 在腾讯云 gt 域名管理 gt 解析 添加一个CNAME记录 和MX记录 复制黏贴即可 5 操作完
  • 模型部署入门教程(五):ONNX 模型的修改与调试

    模型部署入门系列教程持续更新啦 在前两期教程中 我们学习了 PyTorch 模型转 ONNX 模型的方法 了解了如何在原生算子表达能力不足时 为 PyTorch 或 ONNX 自定义算子 一直以来 我们都是通过 PyTorch 来导出 ON
  • Window7下使用VS2017编译VTK-9.0.1的64位动态库教程(超详细)(附编译的库包含32位和64位)

    前言 是一个开源的免费软件系统 主要用于三维计算机图形学 图像处理和可视化 今天编译最新版VTK 9 0 1 并整理成编译教程 提供给新入门的朋友们参考 我使用vs2017编译VTK的64位库 编译32位库的过程和这类似 可以参照本文进行V
  • tiff格式的图片在html中显示

    什么是tiff tiff是一种图片的格式 今天突然看到有一个图片加载失败 控制台调出来一看 有图片地址 tiff格式的 于是就百度查 问朋友 最后查到了一个tiff js的文件 npm 安装 照着别人的教程来并不行 接下来 记录记录我显示t
  • STM32----电容触摸屏,OLED屏和LCD屏

    目录 电容触摸屏 OLED屏 LCD屏 电容触摸屏 充放电电路原理 电路充放电公式 电容触摸按键原理 R 外接电容充放电电阻 Cs TPAD和PCB间的杂散电容 Cx 手指按下时 手指和TPAD之间的电容 开关 电容放电开关 由STM32
  • CST,CET,UTC,GMT,DST,Unix时间戳几种常见时间概述与关系

    1 UTC Universal Time Coordinated 协调世界时 又称世界标准时间 多数的两地时间表都以GMT来表示 但也有些两地时间表上看不到GMT字样 出现的反而是UTC这3个英文字母 究竟何谓UTC 事实上 UTC指的是C
  • android的消息处理机制(图+源码分析)——Looper,Handler,Message

    android的消息处理有三个核心类 Looper Handler和Message 其实还有一个Message Queue 消息队列 但是MQ被封装到Looper里面了 我们不会直接与MQ打交道 因此我没将其作为核心类 下面一一介绍 线程的
  • [MySQL] Centos下的启动和关闭

    MySQL Centos下的启动和关闭 现在主流的Unix系统有两种风格 System V和BSD 他们的区别如下 Linux作为类Unix 同样也存在这两种风格 其中Centos属于System V 本文主要介绍在Centos下 即Sys
  • 如何让人际关系网助你一臂之力?

    如何让人际关系网助你一臂之力 编者按 本文来自First Round Review 他们准备的文章既讲故事 还同时向创业者提供可操作的建议 以助力打造优秀的公司 LinkedIn 早期项目经理Patrick Ewers现如今的工作就是帮助科
  • PCL 部分点云视点问题

    目录 一 问题概述 二 解决方案 1 软件实现 2 代码实现 三 调整之后 一 问题概述 针对CloudCompare软件处理过的pcd格式点云 在使用PCL进行特征点提取 配准等实验中最终显示结果出现点云位置偏差较大的问题 本博客给出解决
  • 基于pytorch神经网络的工业区域用电量预测 完整代码数据

    代码讲解 工业用电量预测 时间序列预测 基于pytorch神经网络的工业用电量预测 完整代码数据 哔哩哔哩 bilibili 本博客付完整代码数据 运行截图 pip install openpyxl i https pypi tuna ts
  • Maven内置了三大特性:属性、Profile和资源过滤来支持构建的灵活性。

    原文地址 http www cnblogs com woms p 5769680 html 内置属性 主要有两个常用内置属性 basedir 表示项目根目录 即包含pom xml文件的目录 version 表示项目版本 POM属性 pom中
  • 《Effective Java》第二版总结

    Effective Java 主要给了78条编码建议 指导 方便开发者开发出 高效 稳定 健壮 设计优良的程序 下面看一下这78条建议 创建和销毁对象 1 考虑用静态工厂方法代替构造器 为了让客户端获取他自身的一个实例 最常用的方法就是提供