আপনার ত্রুটি চাবিকাঠি ধরণ জেনেরিক ঘোষণা হয় F
: F extends Function<T, R>
। যে বক্তব্যটি কাজ করে না তা হ'ল: new Builder<MyInterface>().with(MyInterface::getNumber, 4L);
প্রথমে আপনার একটি নতুন আছে Builder<MyInterface>
। ক্লাসের ঘোষণা তাই বোঝায় T = MyInterface
। আপনার ঘোষণা অনুযায়ী with
, F
একটি হওয়া আবশ্যকFunction<T, R>
যা হয়, Function<MyInterface, R>
এই অবস্থায়। সুতরাং, প্যারামিটারটিকে getter
অবশ্যই প্যারামিটার MyInterface
হিসাবে নিতে হবে (পদ্ধতিটি উল্লেখ MyInterface::getNumber
এবং সন্তুষ্ট MyInterface::getLong
), এবং R
ফাংশনটির দ্বিতীয় প্যারামিটারের মতো একই ধরণের হতে হবে with
। এখন, আসুন দেখুন কি এটি আপনার সমস্ত ক্ষেত্রে রাখে:
// T = MyInterface, F = Function<MyInterface, Long>, R = Long
new Builder<MyInterface>().with(MyInterface::getLong, 4L);
// T = MyInterface, F = Function<MyInterface, Number>, R = Number
// 4L explicitly widened to Number
new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
// T = MyInterface, F = Function<MyInterface, Number>, R = Number
// 4L implicitly widened to Number
new Builder<MyInterface>().<Function<MyInterface, Number>, Number>with(MyInterface::getNumber, 4L);
// T = MyInterface, F = Function<MyInterface, Number>, R = Number
// 4L implicitly widened to Number
new Builder<MyInterface>().with((Function<MyInterface, Number>) MyInterface::getNumber, 4L);
// T = MyInterface, F = Function<MyInterface, Number>, R = Long
// F = Function<T, not R> violates definition, therefore compilation error occurs
// Compiler cannot infer type of method reference and 4L at the same time,
// so it keeps the type of 4L as Long and attempts to infer a match for MyInterface::getNumber,
// only to find that the types don't match up
new Builder<MyInterface>().with(MyInterface::getNumber, 4L);
নিম্নলিখিত বিকল্পগুলির সাহায্যে আপনি এই সমস্যাটি "সমাধান" করতে পারেন:
// stick to Long
new Builder<MyInterface>().with(MyInterface::getLong, 4L);
// stick to Number
new Builder<MyInterface>().with(MyInterface::getNumber, (Number) 4L);
// explicitly convert the result of getNumber:
new Builder<MyInterface>().with(myInstance -> (Long) myInstance.getNumber(), 4L);
// explicitly convert the result of getLong:
new Builder<MyInterface>().with(myInterface -> (Number) myInterface.getLong(), (Number) 4L);
এই বিষয়টির বাইরে, এটি বেশিরভাগই একটি ডিজাইনের সিদ্ধান্ত যার জন্য বিকল্পটি আপনার নির্দিষ্ট অ্যাপ্লিকেশনটির জন্য কোড জটিলতা হ্রাস করে, তাই আপনি যা পছন্দ করেন তা চয়ন করুন।
জাভা ল্যাঙ্গুয়েজ স্পেসিফিকেশন থেকে আপনি নীচে মিথ্যা কাস্টিং ব্যতীত এটি করতে পারবেন না :
বক্সিং রূপান্তর কোনও আদিম ধরণের অভিব্যক্তিটিকে সংশ্লিষ্ট রেফারেন্স প্রকারের এক্সপ্রেশন হিসাবে বিবেচনা করে। বিশেষত, নিম্নলিখিত নয়টি রূপান্তরকে বক্সিং রূপান্তর বলা হয় :
- টাইপ বুলিয়ান থেকে টাইপ করুন বুলিয়ান
- টাইপ বাইট থেকে টাইপ বাইট
- টাইপ শর্ট থেকে শর্ট টাইপ করুন
- চরিত্র থেকে টাইপ চর থেকে টাইপ করুন
- টাইপ int থেকে টাইপ পূর্ণসংখ্যার
- টাইপ দীর্ঘ থেকে টাইপ দীর্ঘ
- টাইপ ফ্লোট থেকে ফ্ল্যাট টাইপ করুন
- টাইপ ডাবল থেকে টাইপ ডাবল
- নাল টাইপ থেকে নাল টাইপ
আপনি স্পষ্টভাবে দেখতে পাচ্ছেন যে লম্বা থেকে সংখ্যায় কোনও অন্তর্নিহিত বক্সিং রূপান্তর নেই এবং লং থেকে সংখ্যায় প্রসারিত রূপান্তর কেবল তখনই ঘটতে পারে যখন সংকলকটি নিশ্চিত হয় যে এটির জন্য কোনও সংখ্যার প্রয়োজন এবং লম্বা নয়। যেহেতু পদ্ধতির রেফারেন্সের মধ্যে একটি সংখ্যার এবং একটি লং সরবরাহকারী 4L এর মধ্যে বিরোধ রয়েছে তাই সংকলক (কোনও কারণে ???) লম্বালটি হ'ল লজিকাল লিপ তৈরি করতে অক্ষম এবং F
এটি একটি সংখ্যাকে ছাড় করুনFunction<MyInterface, Number>
।
পরিবর্তে, আমি ফাংশন স্বাক্ষরটি সামান্য সম্পাদনা করে সমস্যার সমাধান করতে পেরেছি:
public <R> Builder<T> with(Function<T, ? super R> getter, R returnValue) {
return null;//TODO
}
এই পরিবর্তনের পরে, নিম্নলিখিতটি ঘটে:
// doesn't work, as it should not work
new Builder<MyInterface>().with(MyInterface::getLong, (Number), 4L);
// works, as it always did
new Builder<MyInterface>().with(MyInterface::getLong, 4L);
// works, as it should work
new Builder<MyInterface>().with(MyInterface::getNumber, (Number)4L);
// works, as you wanted
new Builder<MyInterface>().with(MyInterface::getNumber, 4L);
সম্পাদনা:
এটিতে আরও কিছু সময় ব্যয় করার পরে, গেটর-ভিত্তিক ধরণের সুরক্ষা কার্যকর করা বিরক্তিকরভাবে কঠিন। এখানে একটি কার্যকারী উদাহরণ যা কোনও বিল্ডারের টাইপ-সুরক্ষা কার্যকর করতে সেটার পদ্ধতি ব্যবহার করে:
public class Builder<T> {
static public interface MyInterface {
//setters
void number(Number number);
void Long(Long Long);
void string(String string);
//getters
Number number();
Long Long();
String string();
}
// whatever object we're building, let's say it's just a MyInterface for now...
private T buildee = (T) new MyInterface() {
private String string;
private Long Long;
private Number number;
public void number(Number number)
{
this.number = number;
}
public void Long(Long Long)
{
this.Long = Long;
}
public void string(String string)
{
this.string = string;
}
public Number number()
{
return this.number;
}
public Long Long()
{
return this.Long;
}
public String string()
{
return this.string;
}
};
public <R> Builder<T> with(BiConsumer<T, R> setter, R val)
{
setter.accept(this.buildee, val); // take the buildee, and set the appropriate value
return this;
}
public static void main(String[] args) {
// works:
new Builder<MyInterface>().with(MyInterface::Long, 4L);
// works:
new Builder<MyInterface>().with(MyInterface::number, (Number) 4L);
// compile time error, as it shouldn't work
new Builder<MyInterface>().with(MyInterface::Long, (Number) 4L);
// works, as it always did
new Builder<MyInterface>().with(MyInterface::Long, 4L);
// works, as it should
new Builder<MyInterface>().with(MyInterface::number, (Number)4L);
// works, as you wanted
new Builder<MyInterface>().with(MyInterface::number, 4L);
// compile time error, as you wanted
new Builder<MyInterface>().with(MyInterface::number, "blah");
}
}
কোনও অবজেক্ট তৈরির জন্য টাইপ-নিরাপদ ক্ষমতা সরবরাহ করা হয়েছে, আশা করি ভবিষ্যতে কোনও সময় আমরা বিল্ডারের কাছ থেকে একটি অপরিবর্তনীয় ডেটা অবজেক্ট ফিরিয়ে আনতে সক্ষম হব (সম্ভবত toRecord()
ইন্টারফেসে কোনও পদ্ধতি যুক্ত করে এবং বিল্ডারকে একটি হিসাবে নির্দিষ্ট করে Builder<IntermediaryInterfaceType, RecordType>
), সুতরাং ফলস্বরূপ অবজেক্টটি সংশোধিত হওয়ার বিষয়ে আপনাকে ভাবতে হবে না। সত্য, এটি একটি নিখুঁত লজ্জার বিষয় যে এটির জন্য একটি টাইপ-নিরাপদ ফিল্ড-নমনীয় নির্মাতা পেতে এত প্রচেষ্টা প্রয়োজন, তবে এটি কিছু নতুন বৈশিষ্ট্য, কোড জেনারেশন বা একটি বিরক্তিকর প্রতিফলন ছাড়া সম্ভবত অসম্ভব।
MyInterface
?